galib247/0040755003643600000000000000000010573536000011372 5ustar mwallwheelgalib247/ChangeLog0100644003643600364360000000146610573535501013213 0ustar mwallmwall2005-01-12 Matthew Wall * makefile: rev to final release number 2005-01-11 Matthew Wall * COPYRIGHT: consolidate * LICENSE: consolidate to COPYRIGHT * README: update quick start section with borland instructions 2004-12-28 Matthew Wall * makevars.win32: do not use precompiled headers - vcpp6 chokes on them and cannot manage them properly. 2004-12-28 Matthew Wall * makefile.win32: added test rule * makevars: added ranlib. some platforms need explicit link to c++ standard libs (e.g. macosx with gcc2) * makefile: split rules for library and examples. added rule for test. 2004-12-27 Matthew Wall * README: minor update and cleanup * makefile: remove ancient cruft galib247/COPYRIGHT0100644003643600364360000000325210573535501012727 0ustar mwallmwallCopyright: Copyright (c) 1995-1996 Massachusetts Institute of Technology (MIT) Copyright (c) 1996-2005 Matthew Wall (the Author) All rights reserved. Distribution Conditions: Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name Massachusetts Institute of Technology (MIT), Matthew Wall, nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. Disclaimer: This software is provided "as is". Any express or implied warranties, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose are disclaimed. In no event shall MIT, Matthew Wall, or the contributors to GAlib be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage. galib247/doc/0040755003643600364360000000000010573535777012221 5ustar mwallmwallgalib247/doc/API.html0100644003643600364360000052507010573535471013515 0ustar mwallmwallGAlib: programming interface Programming interface for GAlib classes
version 2.4

This document describes the programming interface for the library. The section for each class contains a description of the object's purpose followed by the creator signature and member functions. There are also sections for library constants, typedefs, and function signatures.

see also: library overview, class hierarchy, customization


Table of contents





Global Typedefs and Enumerations

typedef float GAProbability, GAProb
typedef enum  _GABoolean {gaFalse, gaTrue} GABoolean, GABool
typedef enum  _GAStatus {gaSuccess, gaFailure} GAStatus
typedef unsigned char GABit




Function Prototypes

GABoolean (*GAGeneticAlgorithm::Terminator)(GAGeneticAlgorithm & ga)
GAGenome& (*GAIncrementalGA::ReplacementFunction)(GAGenome &, GAPopulation &)

     void (*GAPopulation::Initializer)(GAPopulation &)
     void (*GAPopulation::Evaluator)(GAPopulation &)

     void (*GAGenome::Initializer)(GAGenome &)
    float (*GAGenome::Evaluator)(GAGenome &)
      int (*GAGenome::Mutator)(GAGenome &, float)
    float (*GAGenome::Comparator)(const GAGenome &, const GAGenome&)
      int (*GAGenome::SexualCrossover)(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*)
      int (*GAGenome::AsexualCrossover)(const GAGenome&, GAGenome*)

      int (*GABinaryEncoder)(float& value, GABit* bits,
       			       unsigned int nbits, float min, float max)
      int (*GABinaryDecoder)(float& value, const GABit* bits,
       			       unsigned int nbits, float min, float max)



Parameter Names and Command-Line Options

#define name        full name                   short name  default value

gaNminimaxi         minimaxi                    mm          int   gaDefMiniMaxi        = 1
gaNnGenerations     number_of_generations       ngen        int   gaDefNumGen          = 250
gaNpConvergence     convergence_percentage      pconv       float gaDefPConv           = 0.99
gaNnConvergence     generations_to_convergence  nconv       int   gaDefNConv           = 20
gaNpCrossover       crossover_probability       pcross      float gaDefPCross          = 0.9
gaNpMutation        mutation_probability        pmut        float gaDefPMut            = 0.01
gaNpopulationSize   population_size             popsize     int   gaDefPopSize         = 30
gaNnPopulations     number_of_populations       npop        int   gaDefNPop            = 10
gaNpReplacement     replacement_percentage      prepl       float gaDefPRepl           = 0.25
gaNnReplacement     replacement_number          nrepl       int   gaDefNRepl           = 5
gaNnBestGenomes     number_of_best              nbest       int   gaDefNumBestGenomes  = 1
gaNscoreFrequency   score_frequency             sfreq       int   gaDefScoreFrequency1 = 1
gaNflushFrequency   flush_frequency             ffreq       int   gaDefFlushFrequency  = 0
gaNscoreFilename    score_filename              sfile       char* gaDefScoreFilename   = "generations.dat"
gaNselectScores     select_scores               sscores     int   gaDefSelectScores    = GAStatistics::Maximum
gaNelitism          elitism                     el          GABoolean gaDefElitism     = gaTrue
gaNnOffspring       number_of_offspring         noffspr     int   gaDefNumOff          = 2
gaNrecordDiversity  record_diversity            recdiv      GABoolean gaDefDivFlag     = gaFalse
gaNpMigration       migration_percentage        pmig        float gaDefPMig            = 0.1
gaNnMigration       migration_number            nmig        int   gaDefNMig            = 5

Parameters may be specified using the full name strings (for example in parameter files), short name strings (for example on the command line), or explicit member functions (such as those of the genetic algorithm objects). All of the #defined names are simply the full names declared as #defined strings; you can use either the string (e.g. number_of_generations) or the #defined name (e.g. gaNnGenerations), but if you use the #defined name then the compiler will be able to catch your spelling mistakes.

When you specify GAlib arguments on the command line, they must be in name-value pairs. You can use either the long or short name. For example, if my program is called optimizer, the command line for running the program with a population size of 150, mutation rate of 10%, and score filename of evolve.txt would be:

optimizer popsize 150 pmut 0.1 sfile evolve.txt





Global Variables and Global Constants

char* gaErrMsg;    // globally defined pointer to current error message
int  gaDefScoreFrequency1 = 1;   // for non-overlapping populations
int  gaDefScoreFrequency2 = 100; // for overlapping populations

float gaDefLinearScalingMultiplier   = 1.2;
float gaDefSigmaTruncationMultiplier = 2.0;
float gaDefPowerScalingFactor        = 1.0005;
float gaDefSharingCutoff             = 1.0;




Random Number Functions

GAlib includes the following functions for generating random numbers:
     void GARandomSeed(unsigned s = 0)

      int GARandomInt()
      int GARandomInt(int low, int high)

   double GARandomDouble()
   double GARandomDouble(double low, double high)

    float GARandomFloat()
    float GARandomFloat(float low, float high)

      int GARandomBit()

GABoolean GAFlipCoin(float p)

      int GAGaussianInt(int stddev)
    float GAGaussianFloat(float stddev)
   double GAGaussianDouble(double stddev)

   double GAUnitGaussian()

If you call it with no argument, the GARandomSeed function uses the current time multiplied by the process ID (on systems that have PIDs) as the seed for a psuedo-random number generator. On systems with no process IDs it uses only the time. You can specify your own random seed if you like by passing a value to this function. Once a seed has been specified, subsequent calls to GARandomSeed with the same value have no effect. Subsequent calls to GARandomSeed with a different value will re-initialize the random number generator using the new value.

The functions that take low and high as argument return a random number from low to high, inclusive. The functions that take no arguments return a value in the interval [0,1]. GAFlipCoin returns a boolean value based on a biased coin toss. If you give it a value of 1 it will return a 1, if you give it a value of 0.75 it will return a 1 with a 75% chance.

The GARandomBit function is the most efficient way to do unbiased coin tosses. It uses the random bit generator described in Numerical Recipes in C.

The Gaussian functions return a random number from a Gaussian distribution with deviation that you specify. The GAUnitGaussian function returns a number from a unit Gaussian distribution with mean 0 and deviation of 1.

GAlib uses a single random number generator for the entire library. You may not change the random number generator on the fly - it can be changed only when GAlib is compiled. See the config.h and random.h header files for details. By default, GAlib uses the ran2 generator described in Numerical Recipes in C.





Error Handling

Exceptions are not used in GAlib version 2.x. However, some GAlib functions return a status value to indicate whether or not their operation was successful. If a function returns an error status, it posts its error message on the global GAlib error pointer, a global string called gaErrMsg.

By default, GAlib error messages are sent immediately to the error stream. You can disable the immediate printing of error messages by passing gaFalse to the ::GAReportErrors function. Passing a value of gaTrue enables the behavior.

If you would like to redirect the error messages to a different stream, use the ::GASetErrorStream function to assign a new stream. The default stream is the system standard error stream, cerr.

Here are the error control functions and variables:

extern char gaErrMsg[];
void GAReportErrors(GABoolean flag);
void GASetErrorStream(ostream&);




GAGeneticAlgorithm

This is an abstract class that cannot be instantiated. Each genetic algorithm, when instantiated, will have default operators defined for it. See the documentation for the specific genetic algorithm type for details.

The base genetic algorithm class keeps track of evolution statistics such as number of mutations, number of crossovers, number of evaluations, best/mean/worst in each generation, and initial/current population statistics. It also defines the terminator, a member function that specifies the stopping criterion for the algorithm.

You can maximize or minimize by calling the appropriate member function. If you derive your own genetic algorithm, remember that users of your algorithm may need either type of optimization.

Statistics can be written to file each generation or periodically by specifying a flush frequency. Generational scores can be recorded each generation or less frequently by specifying a score frequency.

Parameters such as generations-to-completion, crossover probability and mutation probability can be set by member functions, command-line, or from file.

The evolve member function first calls initialize then calls the step member function until the done member function returns gaTrue. It calls the flushScores member as needed when the evolution is complete. If you evolve the genetic algorithm without using the evolve member function, be sure to call initialize before stepping through the evolution. You can use the step member function to evolve a single generation. You should call flushScores when the evolution is finished so that any buffered scores are flushed.

The names of the individual parameter member functions correspond to the #defined string names. You may set the parameters on a genetic algorithm one at a time (for example, using the nGenerations member function), using a parameter list (for example, using the parameters member function with a GAParameterList), by parsing the command line (for example, using the parameters member function with argc and argv), by name-value pairs (for example, using the set member function with a parameter name and value), or by reading a stream or file (for example, using the parameters member with a filename or stream).

see also: GAParameterList
see also: GAStatistics
see also: Terminators
class hierarchy
class GAGeneticAlgorithm : public GAID
typedefs and constants
GABoolean (*GAGeneticAlgorithm::Terminator)(GAGeneticAlgorithm &)
     enum { MINIMIZE = -1, MAXIMIZE = 1 };
member function index
static GAParameterList& registerDefaultParameters(GAParameterList&);

                   void * userData()
                   void * userData(void *)

                     void initialize(unsigned int seed=0)
                     void evolve(unsigned int seed=0)
                     void step()
                GABoolean done()

GAGeneticAlgorithm::Terminator terminator()
GAGeneticAlgorithm::Terminator terminator(GAGeneticAlgorithm::Terminator)

     const GAStatistics & statistics() const
                    float convergence() const
                      int generation() const
                     void flushScores()

                      int minimaxi() const
                      int minimaxi(int)
                      int minimize()
                      int maximize()
                      int nGenerations() const
                      int nGenerations(unsigned int)
                      int nConvergence() const
                      int nConvergence(unsigned int)
                    float pConvergence() const
                    float pConvergence(float)
                    float pMutation() const
                    float pMutation(float)
                    float pCrossover() const
                    float pCrossover(float)

        GAGenome::SexualCrossover crossover(GAGenome::SexualCrossover func);
        GAGenome::SexualCrossover sexual() const;
       GAGenome::AsexualCrossover crossover(GAGenome::AsexualCrossover func);
       GAGenome::AsexualCrossover asexual() const;

   const GAPopulation & population() const
   const GAPopulation & population(const GAPopulation&)
                    int populationSize() const
                    int populationSize(unsigned int n)
                    int nBestGenomes() const 
                    int nBestGenomes(unsigned int n)

      GAScalingScheme & scaling() const
      GAScalingScheme & scaling(const GAScalingScheme&)
    GASelectionScheme & selector() const
    GASelectionScheme & selector(const GASelectionScheme& s)

                   void objectiveFunction(GAGenome::Evaluator)
                   void objectiveData(const GAEvalData&)

                      int scoreFrequency() const
                      int scoreFrequency(unsigned int frequency)
                      int flushFrequency() const 
                      int flushFrequency(unsigned int frequency)
                    char* scoreFilename() const
                    char* scoreFilename(const char *filename)
                      int selectScores() const
                      int selectScores(GAStatistics::ScoreID which)
                GABoolean recordDiversity() const
                GABoolean recordDiversity(GABoolean flag)

  const GAParameterList & parameters()
  const GAParameterList & parameters(const GAParameterList &)
  const GAParameterList & parameters(int& argc, char** argv, GABoolean flag = gaFalse)
  const GAParameterList & parameters(const char* filename, GABoolean flag = gaFalse);
  const GAParameterList & parameters(istream&, GABoolean flag = gaFalse);

                      int set(const char* s, int v)
                      int set(const char* s, unsigned int v)
                      int set(const char* s, char v)
                      int set(const char* s, const char* v)
                      int set(const char* s, const void* v)
                      int set(const char* s, double v);

                      int write(const char* filename)
                      int write(ostream&)
                      int read(const char* filename)
                      int read(ostream&)
member function descriptions
convergence
Returns the current convergence. The convergence is defined as the ratio of the Nth previous best-of-generation score to the current best-of-generation score.
crossover
Specify the mating method to use for evolution. This can be changed during the course of an evolution. This genetic algorithm uses only sexual crossover.
done
Returns gaTrue if the termination criteria have been met, returns gaFalse otherwise. This function simply calls the completion function that was specified using the terminator member function.
evolve
Initialize the genetic algorithm then evolve it until the termination criteria have been satisfied. This function first calls initialize then calls the step member function until the done member function returns gaTrue. It calls the flushScores member as needed when the evolution is complete. You may pass a seed to evolve if you want to specify your own random seed.
flushFrequency
Use this member function to specify how often the scores should be flushed to disk. A value of 0 means do not write to disk. A value of 100 means to flush the scores every 100 generations.
flushScores
Force the genetic algorithm to flush its generational data to disk. If you have specified a flushFrequency of 0 or specified a scoreFilename of nil then calling this function has no effect.
generation
Returns the current generation.
initialize
Initialize the genetic algorithm. If you specify a seed, this function calls GARandomSeed with that value. If you do not specify a seed, GAlib will choose one for you as described in the random functions section. It then initializes the population and does the first population evaluation.
nBestGenomes
Specify how many 'best' genomes to record. For example, if you specify 10, the genetic algorithm will keep the 10 best genomes that it ever encounters. Beware that if you specify a large number here the algorithm will slow down because it must compare the best of each generation with its current list of best individuals. The default is 1.
nConvergence
Set/Get the number of generations used for the convergence test.
nGenerations
Set/Get the number of generations.
objectiveData
Set the objective data member on all individuals used by the genetic algorithm. This can be changed during the course of an evolution.
objectiveFunction
Set the objective function on all individuals used by the genetic algorithm. This can be changed during the course of an evolution.
parameters
Returns a reference to a parameter list containing the current values of the genetic algorithm parameters.
parameters(GAParameterList&)
Set the parameters for the genetic algorithm. To use this member function you must create a parameter list (an array of name-value pairs) then pass it to the genetic algorithm.
parameters(int& argc, char** argv, GABoolean flag = gaFalse)
Set the parameters for the genetic algorithm. Use this member function to let the genetic algorithm parse your command line for arguments that GAlib understands. This method decrements argc and moves the pointers in argv appropriately to remove from the list the arguments that it understands. If you pass gaTrue as the third argument then the method will complain about any command-line arguments that are not recognized by this genetic algorithm.
parameters(char* filename, GABoolean flag = gaFalse)
parameters(istream&, GABoolean flag = gaFalse)
Set the parameters for the genetic algorithm. This version of the parameters member function will parse the specified file or stream for parameters that the genetic algorithm understands. If you pass gaTrue as the second argument then the method will complain about any parameters that are not recognized by this genetic algorithm.
pConvergence
Set/Get the convergence percentage. The convergence is defined as the ratio of the Nth previous best-of-generation score to the current best-of-generation score. N is defined by the nConvergence member function.
pCrossover
Set/Get the crossover probability.
pMutation
Set/Get the mutation probability.
population
Set/Get the population. Returns a reference to the current population.
populationSize
Set/Get the population size. This can be changed during the course of an evolution.
recordDiversity
Convenience function for specifying whether or not to calculate diversity. Since diversity calculations require comparison of each individual with every other, recording this statistic can be expensive. The default is gaFalse (diversity is not recorded).
registerDefaultParameters
Each genetic algorithm defines this member function to declare the parameters that work with it. Pass a parameter list to this function and this function will configure the list with the default parameter list and values for the genetic algorithm class from which you called it. This is a statically defined function, so invoke it using the class name of the genetic algorithm whose parameters you want to use, for example, GASimpleGA::registerDefaultParameters(list). The default parameters for the base genetic algorithm class are:
  • flushFrequency
  • minimaxi
  • nBestGenomes
  • nGenerations
  • nConvergence
  • pConvergence
  • pCrossover
  • pMutation
  • populationSize
  • recordDiversity
  • scoreFilename
  • scoreFrequency
  • selectScores
scaling
Set/Get the scaling scheme. The specified scaling scheme must be derived from the GAScalingScheme class. This can be changed during the course of an evolution.
scoreFilename
Specify the name of the file to which the scores should be recorded.
scoreFrequency
Specify how often the generational scores should be recorded. The default depends on the type of genetic algorithm that you are using. You can record mean, max, min, stddev, and diversity for every n generations.
selector
Set/Get the selection scheme for the genetic algorithm. The selector is used to pick individuals from a population before mating and mutation occur. This can be changed during the course of an evolution.
selectScores
This function is used to specify which scores should be saved to disk. The argument is the logical OR of the following values: Mean, Maximum, Minimum, Deviation, Diversity (all defined in the scope of the GAStatistics object). To record all of the scores, pass GAStatistics::AllScores. When written to file, the format is as follows:
generation  TAB  mean  TAB  max  TAB  min  TAB deviation  TAB  diversity NEWLINE
set
Set individual parameters for the genetic algorithm. The first argument should be the full- or short-name of the parameter you wish to set. The second argument is the value to which you would like to set the parameter.
statistics
Returns a reference to the statistics object in the genetic algorithm. The statistics object maintains information such as best, worst, mean, and standard deviation, and diversity of each generation as well as a separate population with the best individuals ever encountered by the genetic algorithm.
step
Evolve the genetic algorithm for one generation.
terminator
Set/Get the termination function. The genetic algorithm is complete when the completion function returns gaTrue. The function must have the proper signature.
userData
Set/Get the userData member of the genetic algorithm. This member is a generic pointer to any information that needs to be stored with the genetic algorithm.




GASimpleGA (non-overlapping populations)

This genetic algorithm is the 'simple' genetic algorithm that Goldberg describes in his book. It uses non-overlapping populations. When you create a simple genetic algorithm, you must specify either an individual or a population of individuals. The new genetic algorithm will clone the individual(s) that you specify to make its own population. You can change most of the genetic algorithm behaviors after creation and during the course of the evolution.

The simple genetic algorithm creates an initial population by cloning the individual or population you pass when you create it. Each generation the algorithm creates an entirely new population of individuals by selecting from the previous population then mating to produce the new offspring for the new population. This process continues until the stopping criteria are met (determined by the terminator).

Elitism is optional. By default, elitism is on, meaning that the best individual from each generation is carried over to the next generation. To turn off elitism, pass gaFalse to the elitist member function.

The score frequency for this genetic algorithm defaults to 1 (it records the best-of-generation every generation). The default scaling is Linear, the default selection is RouletteWheel.

see also: GAGeneticAlgorithm
class hierarchy
class GASimpleGA : public GAGeneticAlgorithm
constructors
GASimpleGA(const GAGenome&)
GASimpleGA(const GAPopulation&)
GASimpleGA(const GASimpleGA&)
member function index
static GAParameterList& registerDefaultParameters(GAParameterList&);

           GASimpleGA & operator++()

              GABoolean elitist() const
              GABoolean elitist(GABoolean flag)
member function descriptions
elitist
Set/Get the elitism flag. If you specify gaTrue, the genetic algorithm will copy the best individual from the previous population into the current population if no individual in the current population is any better.
operator++
The increment operator evolves the genetic algorithm's population by one generation by calling the step member function.
registerDefaultParameters
This function adds to the specified list parameters that are of interest to this genetic algorithm. The default parameters for the simple genetic algorithm are the parameters for the base genetic algorithm class plus the following:
  • elitism




GASteadyStateGA (overlapping populations)

This genetic algorithm is similar to the algorithms described by DeJong. It uses overlapping populations with a user-specifiable amount of overlap. The algorithm creates a population of individuals by cloning the genome or population that you pass when you create it. Each generation the algorithm creates a temporary population of individuals, adds these to the previous population, then removes the worst individuals in order to return the population to its original size.

You can select the amount of overlap between generations by specifying the pReplacement parameter. This is the percentage of the population that should be replaced each generation. Newly generated offspring are added to the population, then the worst individuals are destroyed (so the new offspring may or may not make it into the population, depending on whether they are better than the worst in the population).

If you specify a replacement percentage, then that percentage of the population will be replaced each generation. Alternatively, you can specify a number of individuals (less than the number in the population) to replace each generation. You cannot specify both - in a parameter list containing both parameters, the latter is used.

The score frequency for this genetic algorithm defaults to 100 (it records the best-of-generation every 100th generation). The default scaling is Linear, the default selection is RouletteWheel.

see also: GAGeneticAlgorithm
class hierarchy
class GASteadyStateGA : public GAGeneticAlgorithm
constructors
GASteadyStateGA(const GAGenome&)
GASteadyStateGA(const GAPopulation&)
GASteadyStateGA(const GASteadyStateGA&)
member function index
static GAParameterList& registerDefaultParameters(GAParameterList&);

      GASteadyStateGA & operator++()

                  float pReplacement() const
                  float pReplacement(float percentage)
                    int nReplacement() const
                    int nReplacement(unsigned int)
member function descriptions
nReplacement
Specify a number of individuals to replace each generation. When you specify a number of individuals to replace, the pReplacement value is set to 0.
operator++
The increment operator evolves the genetic algorithm's population by one generation by calling the step member function.
pReplacement
Specify a percentage of the population to replace each generation. When you specify a replacement percentage, the nReplacement value is set to 0.
registerDefaultParameters
This function adds to the specified list parameters that are of interest to this genetic algorithm. The default parameters for the steady-state genetic algorithm are the parameters for the base genetic algorithm class plus the following:
  • pReplacement
  • nReplacement




GAIncrementalGA (overlapping populations with 1 or 2 children per generation)

This genetic algorithm is similar to those based on the GENITOR model. It uses overlapping populations, but very little overlap (only one or two individuals get replaced each generation). The default replacement scheme is WORST. A replacement function is required only if you use CUSTOM or CROWDING as the replacement scheme. You can do DeJong-style crowding by specifying a distance function with the CROWDING option. (for best DeJong-style results, derive your own genetic algorithm)

You can specify the number of children that are generated in each 'generation' by using the nOffspring member function. Since this genetic algorithm is based on a two-parent crossover model, the number of offspring must be either 1 or 2. The default is 2.

Use the replacement method to specify which type of replacement the genetic algorithm should use. The replacement strategy determines how the new children will be inserted into the population. If you want the new child to replace one of its parents, use the Parent strategy. If you want the child to replace a random population member, use the Random strategy. If you want the child to replace the worst population member, use the Worst strategy.

If you specify CUSTOM or CROWDING you must also specify a replacement function with the proper signature. This function is used to pick which genome will be replaced. The first argument passed to the replacement function is the individual that is supposed to go into the population. The second argument is the population into which the individual is supposed to go. The replacement function should return a reference to the genome that the individual should replace. If no replacement should take place, the replacement function should return a reference to the individual.

The score frequency for this genetic algorithm defaults to 100 (it records the best-of-generation every 100th generation). The default scaling is Linear, the default selection is RouletteWheel.

see also: GAGeneticAlgorithm
class hierarchy
class GAIncrementalGA : public GAGeneticAlgorithm
typedefs and constants
GAGenome& (*GAIncrementalGA::ReplacementFunction)(GAGenome &, GAPopulation &)

enum ReplacementScheme {
    RANDOM = GAPopulation::RANDOM,
    BEST = GAPopulation::BEST,
    WORST = GAPopulation::WORST,
    CUSTOM = -30,
    CROWDING = -30,
    PARENT = -10
    };
constructors
GAIncrementalGA(const GAGenome&)
GAIncrementalGA(const GAPopulation&)
GAIncrementalGA(const GAIncrementalGA&)
member function index
static GAParameterList& registerDefaultParameters(GAParameterList&);

      GASteadyStateGA & operator++()

      ReplacementScheme replacement()
      ReplacementScheme replacement(ReplacementScheme, ReplacementFunction f = NULL)

                    int nOffspring() const
                    int nOffspring(unsigned int n)
member function descriptions
nOffspring
The incremental genetic algorithm can produce either one or two individuals each generation. Use this member function to specify how many individuals you would like.
operator++
The increment operator evolves the genetic algorithm's population by one generation by calling the step member function.
registerDefaultParameters
This function adds to the specified list parameters that are of interest to this genetic algorithm. The default parameters for the incremental genetic algorithm are the parameters for the base genetic algorithm class plus the following:
  • nOffspring
replacement
Specify a replacement method. The scheme can be one of
  • GAIncrementalGA::RANDOM
  • GAIncrementalGA::BEST
  • GAIncrementalGA::WORST
  • GAIncrementalGA::CUSTOM
  • GAIncrementalGA::CROWDING
  • GAIncrementalGA::PARENT
If you specify custom or crowding replacement then you must also specify a function. The replacement function takes two arguments: the individual to insert and the population into which it will be inserted. The replacement function should return a reference to the genome that should be replaced. If no replacement should take place, the replacement function should return a reference to the individual passed to it.




GADemeGA (parallel populations with migration)

This genetic algorithm has multiple, independent populations. It creates the populations by cloning the genome or population that you pass when you create it.

Each population evolves using a steady-state genetic algorithm, but each generation some individuals migrate from one population to another. The migration algorithm is deterministic stepping-stone; each population migrates a fixed number of its best individuals to its neighbor. The master population is updated each generation with best individual from each population.

If you want to experiment with other migration methods, derive a new class from this one and define a new migration operator. You can change the evolution behavior by defining a new step method in a derived class.

see also: GAGeneticAlgorithm
class hierarchy
class GADemeGA : public GAGeneticAlgorithm
typedefs and constants
enum { ALL= -1 };
constructors
GADemeGA(const GAGenome&)
GADemeGA(const GAPopulation&)
GADemeGA(const GADemeGA&)
member function index
static GAParameterList& registerDefaultParameters(GAParameterList&);

               void migrate()
         GADemeGA & operator++()

const GAPopulation& population(unsigned int i) const
const GAPopulation& population(int i, const GAPopulation&)
                int populationSize(unsigned int i) const
                int populationSize(int i, unsigned int n)
                int nReplacement(unsigned int i) const
                int nReplacement(int i, unsigned int n)
                int nMigration() const
                int nMigration(unsigned int i)
                int nPopulations() const
                int nPopulations(unsigned int i)
const GAStatistics& statistics() const
const GAStatistics& statistics(unsigned int i) const
member function descriptions
nMigration
Specify the number of individuals to migrate each generation. Each population will migrate this many of its best individuals to the next population (the stepping-stone migration model). The individuals replace the worst individuals in the receiving population.
nReplacement
Specify a number of individuals to replace each generation. When you specify a number of individuals to replace, the pReplacement value is set to 0. The first argument specifies which population should be modified. Use GADemeGA::ALL to apply to all populations.
operator++
The increment operator evolves the genetic algorithm's population by one generation by calling the step member function.
pReplacement
Specify a percentage of the population to replace each generation. When you specify a replacement percentage, the nReplacement value is set to 0. The first argument specifies which population should be modified. Use GADemeGA::ALL to apply to all populations.
registerDefaultParameters
This function adds parameters to the specified list that are of interest to this genetic algorithm. The default parameters for the deme genetic algorithm are the parameters for the base genetic algorithm class plus the following:
  • nMigration
  • nPopulations




Terminators

Completion functions are used to determine whether or not a genetic algorithm is finished. The done member function simply calls the completion function to determine whether or not the genetic algorithm should continue. The predefined completion functions use generation and convergence to determine whether or not the genetic algorithm is finished.

The completion function returns gaTrue when the genetic algorithm should finish, and gaFalse when the genetic algorithm should continue.

In this context, convergence refers to the the similarity of the objective scores, not similarity of underlying genetic structure. The built-in convergence measures use the best-of-generation scores to determine whether or not the genetic algorithm has plateaued.

GABoolean GAGeneticAlgorithm::TerminateUponGeneration(GAGeneticAlgorithm &)
GABoolean GAGeneticAlgorithm::TerminateUponConvergence(GAGeneticAlgorithm &)
GABoolean GAGeneticAlgorithm::TerminateUponPopConvergence(GAGeneticAlgorithm &)

TerminateUponGeneration
This function compares the current generation to the specified number of generations. If the current generation is less than the requested number of generations, it returns gaFalse. Otherwise, it returns gaTrue.

TerminateUponConvergence
This function compares the current convergence to the specified convergence value. If the current convergence is less than the requested convergence, it returns gaFalse. Otherwise, it returns gaTrue.

Convergence is a number between 0 and 1. A convergence of 1 means that the nth previous best-of-generation is equal to the current best-of-generation. When you use convergence as a stopping criterion you must specify the convergence percentage and you may specify the number of previous generations against which to compare. The genetic algorithm will always run at least this many generations.

TerminateUponPopConvergence
This function compares the population average to the score of the best individual in the population. If the population average is within pConvergence of the best individual's score, it returns gaTrue. Otherwise, it returns gaFalse.

For details about how to write your own termination function, see the customizations page.





Replacement Schemes

The replacement scheme is used by the incremental genetic algorithm to determine how a new individual should be inserted into a population. Valid replacement schemes include:
GAIncrementalGA::RANDOM
GAIncrementalGA::BEST
GAIncrementalGA::WORST
GAIncrementalGA::CUSTOM
GAIncrementalGA::CROWDING
GAIncrementalGA::PARENT

In general, replace worst produces the best results. Replace parent is useful for basic speciation, and custom replacement can be used when you want to do your own type of speciation.

If you specify CUSTOM or CROWDING replacement then you must also specify a replacement function. The replacement function takes as arguments an individual and the population into which the individual should be placed. It returns a reference to the genome that the individual should replace. If the individual should not be inserted into the population, the function should return a reference to the individual.

Any replacement function must have the following function prototype:

typedef GAGenome& (*GAIncrementalGA::ReplacementFunction)(GAGenome &, GAPopulation &);
The first argument is the genome that will be inserted into the population, the second argument is the population into which the genome should be inserted. The function should return a reference to the genome that will be replaced. If no replacement occurs, the function should return a reference to the original genome.

For details about how to write your own replacement function, see the customizations page.





GAEvalData

The evaluation data object is a generic base class for genome- and/or population-specific data. Whereas the userData member of the genome is shared by all genomes in a population, the evalData member is unique to each genome. The base class defines the copy/clone interface for the evaluation data object. Your derived classes should use this mechanism. Any derived class must define a clone and copy member function. These will be called by the base class when the evaluation data is cloned/copied by the genomes/populations.
class hierarchy
class GAEvalData : public GAID
constructors
GAEvalData()
GAEvalData(const GAEvalData&) 
member functions
GAEvalData* clone() const
       void copy(const GAEvalData&)




GAGenome

The genome is a virtual base class and cannot be instantiated. It defines a number of constants and function prototypes specific to the genome and its derived classes.

The dimension is used to specify which dimension is being referred to in multi-dimensional genomes. The clone method specifies whether to clone the entire genome (a new genome with contents identical to the original will be created) or just the attributes of the genome (a new genome with identical characteristics will be created). In both cases the caller is responsible for deleting the memory allocated by the clone member function. The resize constants are used when specifying a resizable genome's resize behavior.

The genetic operators for genomes are functions that take generic genomes as their arguments. This makes it possible to define new behaviors for existing genome classes without deriving a new class. The genetic operators are defined with the following prototypes:

Instructions for deriving your own genome class are in the customization page.

class hierarchy
class GAGenome : public GAID
typedefs and constants
enum GAGenome::Dimension { LENGTH, WIDTH, HEIGHT, DEPTH }
enum GAGenome::CloneMethod { CONTENTS, ATTRIBUTES }
enum { FIXED_SIZE = -1, ANY_SIZE = -10 }
    float (*GAGenome::Evaluator)(GAGenome &)
     void (*GAGenome::Initializer)(GAGenome &)
      int (*GAGenome::Mutator)(GAGenome &, float)
    float (*GAGenome::Comparator)(const GAGenome &, const GAGenome&)
      int (*GAGenome::SexualCrossover)(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*);
      int (*GAGenome::AsexualCrossover)(const GAGenome&, GAGenome*);
member function index
              virtual void copy(const GAGenome & c)
        virtual GAGenome * clone(CloneMethod flag = CONTENTS)

                     float score(GABoolean flag = gaFalse)
                     float score(float s)
                       int nevals()

                     float evaluate(GABoolean flag = gaFalse)
       GAGenome::Evaluator evaluator() const
       GAGenome::Evaluator evaluator(GAGenome::Evaluator func)

                      void initialize()
       GAGenomeInitializer initializer() const
       GAGenomeInitializer initializer(GAGenome::Initializer func)

                       int mutate(float pmutation)
         GAGenome::Mutator mutator() const
         GAGenome::Mutator mutator(GAGenome::Mutator func)

                     float compare(const GAGenome& g) const
      GAGenome::Comparator comparator() const 
      GAGenome::Comparator comparator(GAGenome::Comparator c)

 GAGenome::SexualCrossover crossover(GAGenome::SexualCrossover func)
 GAGenome::SexualCrossover sexual()
GAGenome::AsexualCrossover crossover(GAGenome::AsexualCrossover func)
GAGenome::AsexualCrossover asexual()

      GAGeneticAlgorithm * geneticAlgorithm() const
      GAGeneticAlgorithm * geneticAlgorithm(GAGeneticAlgorithm &)
                    void * userData() const
                    void * userData(void * data)
              GAEvalData * evalData() const
              GAEvalData * evalData(void * data)

               virtual int read(istream &)
               virtual int write(ostream &) const

               virtual int equal(const GAGenome &) const
               virtual int notequal(const GAGenome &) const
These operators call the corresponding virtual members so that they will work on any properly derived genome class.
              friend int operator==(const GAGenome&, const GAGenome&)
              friend int operator!=(const GAGenome&, const GAGenome&)
        friend ostream & operator<<(ostream&, const GAGenome&)
        friend istream & operator>>(istream&, GAGenome&)
member function descriptions
clone
This method allocates space for a new genome whereas the copy method uses the space of the genome to which it belongs.
compare
Compare two genomes. The comparison can be genotype- or phenotype-based. The comparison returns a value greater than or equal to 0. 0 means the two genomes are identical (no diversity). The exact meaning of the comparison is up to you.
comparator
Set/Get the comparison method. The comparator must have the correct signature.
copy
The copy member function is called by the base class' operator= and clone members. You can use it to copy the contents of a genome into an existing genome.
crossover
Each genome class can define its preferred mating method. Use this method to assign the preferred crossover for a genome instance.
equal
notequal
'equal' and 'notequal' are genome-specific. See the documentation for each genome class for specific details about what 'equal' means. For example, genomes that have identical contents but different allele sets may or may not be considered equal. By default, notequal just calls the equal function, but you can override this in derived classes if you need to optimize the comparison.
evalData
Set/Get the object used to store genome-specific evaluation data. Each genome owns its own evaluation data object; cloning a genome clones the evaluation data as well.
evaluate
Invoke the genome's evaluation function. If you call this member with gaTrue, the evaluation function is called no matter what (assuming one has been assigned to the genome). By default, the argument to this function is gaFalse, so the genome's evaluation function is called only if the state of the genome has not changed since the last time the evaluator was invoked.
evaluator
Set/Get the function used to evaluate the genome.
geneticAlgorithm
The member function returns a pointer to the genetic algorithm that 'owns' the genome. If this function returns nil then the genome has no genetic algorithm owner.
initialize
Calls the initialization function for the genome.
initializer
Set/Get the initialization method. The initializer must have the correct signature.
mutate
Calls the mutation method for the genome. The value is typically the mutation likliehood, but the exact interpretation of this value is up to the designer of the mutation method.
mutator
Set/Get the mutation method. The mutator must have the correct signature.
nevals
Returns the number of objective function evaluations since the genome was initialized.
operator==
operator!=
operator<<
operator>>
These methods call the associated virtual member functions. They can be used on any generic genome. If the derived class was properly defined, the appropriate derived functions will be called and the functions will operate on the derived classes rather than the base class.
read
Fill the genome with the data read from the specified stream.
sexual
asexual
Returns a pointer to the preferred mating method for this genome. If this function returns nil, no mating method has been defined for the genome. The genetic algorithm object has ultimate control over the mating method that is actually used in the evolution.
score
Returns the objective score of the genome using the objective function assigned to the genome. If no objective function has been assigned and no score has been set, a score of 0 will be returned. If the score function is called with an argument, the genome's objective score is set to that value (useful for population-based objective functions in which the population object does the evaluations).
userData
Each genome contains a generic pointer to user-specifiable data. Use this member function to set/get that pointer. Notice that cloning a genome will cause the cloned genome to refer to the same user data pointer as the original; the user data is not cloned as well. So all genomes in a population refer to the same user data.
write
Send the contents of the genome to the specified stream.




GAListGenome<T>

The list genome is a template class. It is derived from the GAGenome class as well as the GAList<> class. It can be used for order-based representations or variable length sequences as well as traditional applications of lists.

You must define an initialization operator for this class. The default initializer is NoInitializer - if you do not assign an initialization operator then you'll get errors about no initializer defined when you try to initialize the genome.

see also: GAList
see also: GAGenome
class hierarchy
class GAListGenome<T> : public GAList<T>, public GAGenome
constructors
GAListGenome(GAGenome::Evaluator objective = NULL, void * userData = NULL)
GAListGenome(const GAListGenome<T> &)
genetic operators for this class
GAListGenome<>::DestructiveMutator
GAListGenome<>::SwapMutator
GAListGenome<>::OnePointCrossover
GAListGenome<>::PartialMatchCrossover
GAListGenome<>::OrderCrossover
GAListGenome<>::CycleCrossover
default genetic operators
initialization:  GAGenome::NoInitializer
    comparison:  GAGenome::NoComparator
      mutation:  GAListGenome<>::SwapMutator
     crossover:  GAListGenome<>::OnePointCrossover




GATreeGenome<T>

The tree genome is a template class. It is derived from the GAGenome class as well as the GATree<> class. The tree genome can be used for direct manipulation of tree objects. It can be used to represent binary trees as well as non-binary trees.

You must define an initialization operator for this class. The default initializer is NoInitializer - if you do not assign an initialization operator then you'll get errors about no initializer defined when you try to initialize the genome.

see also: GATree
see also: GAGenome
class hierarchy
class GATreeGenome<T> : public GATree<T>, public GAGenome
constructors
GATreeGenome(GAGenome::Evaluator objective = NULL, void * userData = NULL)
GATreeGenome(const GATreeGenome<T> &)
genetic operators for this class
GATreeGenome<>::DestructiveMutator
GATreeGenome<>::SwapSubtreeMutator
GATreeGenome<>::SwapNodeMutator
GATreeGenome<>::OnePointCrossover
default genetic operators
initialization:  GAGenome::NoInitializer
    comparison:  GAGenome::NoComparator
      mutation:  GATreeGenome<>::SwapSubtreeMutator
     crossover:  GATreeGenome<>::OnePointCrossover




GAStringGenome

The string genome can be used for order-based applications, variable length string applications, or non-binary allele set alphabets. The allele set defines the possible values that each element in the string may assume.

The string genome is a specialization of the array genome with alleles. The specialization is of type char. You must create an allele set or array of allele sets before you can instantiate this genome.

If you create a string genome using a single allele set, each element in the genome will use that allele set to determine its value. If you create a string genome using an allele set array, the string will have a length equal to the number of elements in the array and each element of the string will be governed by the allele set corresponding to its location in the string.

To use the string genome in your code, you must include the string genome header file in each of your files that uses the string genome. You must also include the string genome source file (it contains template specialization code) in one (and only one) of your source files. Including the string genome source file will force the compiler to use the string specializations. If you do not include the string genome source file you will get the generic array routines instead (and some of the allele methods will not work as expected).

see also: GA1DArrayAlleleGenome
see also: GAAlleleSet
see also: GAAlleleSetArray
class hierarchy
typedef GAAlleleSet<char>                    GAStringAlleleSet
typedef GAAlleleSetCore<char>                GAStringAlleleSetCore
typedef GAAlleleSetArray<char>               GAStringAlleleSetArray
typedef GA1DArrayAlleleGenome<char>          GAStringGenome
constructors
GAStringGenome(unsigned int length,
               const GAStringAlleleSet &,
               GAGenome::Evaluator objective = NULL,
               void * userData = NULL)
GAStringGenome(const GAStringAlleleSetArray &,
               GAGenome::Evaluator objective = NULL,
               void * userData = NULL)
GAStringGenome(const GAStringGenome&)
genetic operators for this class
GAStringGenome::UniformInitializer
GAStringGenome::OrderedInitializer
GAStringGenome::FlipMutator
GAStringGenome::SwapMutator
GAStringGenome::UniformCrossover
GAStringGenome::EvenOddCrossover
GAStringGenome::OnePointCrossover
GAStringGenome::TwoPointCrossover
GAStringGenome::PartialMatchCrossover
GAStringGenome::OrderCrossover
GAStringGenome::CycleCrossover
default genetic operators
initialization:  GAStringGenome::UniformInitializer
    comparison:  GAStringGenome::ElementComparator
      mutation:  GAStringGenome::FlipMutator
     crossover:  GAStringGenome::UniformCrossover




GARealGenome

The real number genome was designed to be used for applications whose representation requires an array of (possibly bounded) real number parameters. The elements of the array can assume bounded values, discretized bounded values, or enumerated values, depending on the type of allele set that is used to create the genome. You can mix the bounding within the genome by specifying an appropriate array of allele sets. The allele set defines the possible values that each element in the genome may assume.

The real number genome is a specialization of the array genome with alleles. The specialization is of type float. You must create an allele set or array of allele sets before you can instantiate this genome.

If you create a real number genome using a single allele set, each element in the genome will use that allele set to determine its value. If you create a real number genome using an allele set array, the genome will have a length equal to the number of elements in the array and each element of the real number will be governed by the allele set corresponding to its location in the genome.

To use the real genome in your code, you must include the real genome header file in each of your files that uses the real genome. You must also include the real genome source file (it contains template specialization code) in one (and only one) of your source files. Including the real genome source file will force the compiler to use the real specializations. If you do not include the real genome source file you will get the generic array routines instead (and some of the allele methods will not work as expected).

see also: GA1DArrayAlleleGenome
see also: GAAlleleSet see also: GAAlleleSetArray
class hierarchy
typedef GAAlleleSet<float>                    GARealAlleleSet
typedef GAAlleleSetCore<float>                GARealAlleleSetCore
typedef GAAlleleSetArray<float>               GARealAlleleSetArray
typedef GA1DArrayAlleleGenome<float>          GARealGenome
constructors
GARealGenome(unsigned int length,
             const GARealAlleleSet &,
             GAGenome::Evaluator objective = NULL,
             void * userData = NULL)
GARealGenome(const GARealAlleleSetArray &,
             GAGenome::Evaluator objective = NULL,
             void * userData = NULL)
GARealGenome(const GARealGenome&)
genetic operators for this class
GARealGenome::UniformInitializer
GARealGenome::OrderedInitializer
GARealGenome::FlipMutator
GARealGenome::SwapMutator
GARealGaussianMutator
GARealGenome::UniformCrossover
GARealGenome::EvenOddCrossover
GARealGenome::OnePointCrossover
GARealGenome::TwoPointCrossover
GARealGenome::PartialMatchCrossover
GARealGenome::OrderCrossover
GARealGenome::CycleCrossover
GARealBlendCrossover
GARealArithmeticCrossover
default genetic operators
initialization:  GARealGenome::UniformInitializer
    comparison:  GARealGenome::ElementComparator
      mutation:  GARealGaussianMutator
     crossover:  GARealGenome::UniformCrossover




GABin2DecGenome
This genome is an implementation of the traditional method for converting binary strings to decimal values. It contains a mechanism for customized encoding of the bit string; binary-to-decimal and one form of Gray coding are built in to the library. The default is binary-to-decimal mapping (counting in base 2). To use this genome, you must create a mapping of bits to decimal values by specifying how many bits will be used to represent what bounded numbers. The binary-to-decimal genome is derived from the 1DBinaryStringGenome class.

You must create a phenotype before you can instantiate this genome. The phenotype defines how bits should map into decimal values and vice versa. A single binary-to-decimal phenotype contains the number of bits used to represent the decimal value and the minimum and maximum decimal values to which the set of bits will map.

see also: GA1DBinaryStringGenome
see also: GABin2DecPhenotype
see also: GACrossover
class hierarchy
class GABin2DecGenome : public GA1DBinaryStringGenome
constructors
GABin2DecGenome(const GABin2DecPhenotype &,
                GAGenome::Evaluator objective = NULL,
                void * userData = NULL)
GABin2DecGenome(const GABin2DecGenome&)
member function index
const GABin2DecPhenotype& phenotypes(const GABin2DecPhenotype &)
const GABin2DecPhenotype& phenotypes() const
                       int nPhenotypes() const
                     float phenotype(unsigned int n) const
                     float phenotype(unsigned int n, float value)

                      void encoder(GABinaryEncoder)
                      void decoder(GABinaryDecoder)
member function descriptions
encoder
decoder
Use these member functions to set the encoder/decoder for the genome. These functions determine what method will be used for converting the binary bits to decimal numbers. The functions that you specify here must have the proper signature.
nPhenotype
Returns the number of phenotypes (i.e. the number of decimal values represented) in the genome.
phenotypes
Set/Get the mapping from binary to decimal numbers.
phenotype
Set/Get the specified phenotype.
default genetic operators
initialization:  GA1DBinaryStringGenome::UniformInitializer
    comparison:  GA1DBinaryStringGenome::BitComparator
      mutation:  GA1DBinaryStringGenome::FlipMutator
     crossover:  GA1DBinaryStringGenome::OnePointCrossover
   de/encoding:  GABinaryEncode/GABinaryDecode
additional information
Conversion functions are defined for transforming strings of bits to decimal values and vice versa. The function prototypes for the encoding (decimal-to-binary) and decoding (binary-to-decimal) are defined as follows:
typedef int (*GABinaryEncoder)(float& value, GABit* bits,
			       unsigned int nbits, float min, float max);
typedef int (*GABinaryDecoder)(float& value, const GABit* bits,
			       unsigned int nbits, float min, float max);

The library includes the following binary-to-decimal/decimal-to-binary converters:

GABinaryEncode/GABinaryDecode
Convert using a binary coding scheme.
GAGrayEncode/GAGrayDecode
Convert using a Gray coding scheme.




GA1DBinaryStringGenome
The binary string genome is derived from the GABinaryString and GAGenome classes. It is a string of 1s and 0s whose length may be fixed or variable.

The genes in this genomes are bits. The alleles for each bit are 0 and 1.

see also: GABinaryString
see also: GAGenome
class hierarchy
class GA1DBinaryStringGenome : public GABinaryString, public GAGenome
constructors
GA1DBinaryStringGenome(unsigned int x,
                       GAGenome::Evaluator objective = NULL,
                       void * userData = NULL)
GA1DBinaryStringGenome(const GA1DBinaryStringGenome&)
member function index
short gene(unsigned int x = 0) const
short gene(unsigned int, short value)
  int length() const
  int length(int l)
  int resize(int x)
  int resizeBehaviour() const
  int resizeBehaviour(unsigned int minx, unsigned int maxx)
 void copy(const GA1DBinaryStringGenome &,
           unsigned int xdest, unsigned int xsrc, unsigned int length)
 void set(unsigned int x, unsigned int length)
 void unset(unsigned int x, unsigned int length)
member function descriptions
copy
Copy the specified bits from the designated genome.
gene
Set/Get the specified bit.
length
Set/Get the length of the bit string.
resize
Set the length of the bit string.
resizeBehaviour
Set/Get the resize behavior. The min value specifies the minimum allowable length, the max value specifies the maximum allowable length. If min and max are equal, the genome is not resizable.

Use the resizeBehaviour and resize member functions to control the size of the genome. The default behavior is fixed size. Using the resizeBehaviour method you can specify minimum and maximum values for the size of the genome. If you specify minimum and maximum as the same values then fixed size is assumed. If you use the resize method to specify a size that is outside the bounds set earlier using resizeBehaviour, the bounds will be 'stretched' to accommodate the value you specify with resize. Conversely, if the values you specify with resizeBehaviour conflict with the genome's current size, the genome will be resized to accommodate the new values.

When resizeBehaviour is called with no arguments, it returns the maximum size if the genome is resizable, or GAGenome::FIXED_SIZE if the size is fixed.

set
unset
Set/Unset the bits in the specified range. If you specify a range that is not represented by the genome, the range that you specified will be clipped to fit the genome.
genetic operators for this class
GA1DBinaryStringGenome::UniformInitializer
GA1DBinaryStringGenome::SetInitializer
GA1DBinaryStringGenome::UnsetInitializer
GA1DBinaryStringGenome::FlipMutator
GA1DBinaryStringGenome::BitComparator
GA1DBinaryStringGenome::UniformCrossover
GA1DBinaryStringGenome::EvenOddCrossover
GA1DBinaryStringGenome::OnePointCrossover
GA1DBinaryStringGenome::TwoPointCrossover
default genetic operators
initialization:  GA1DBinaryStringGenome::UniformInitializer
    comparison:  GA1DBinaryStringGenome::BitComparator
      mutation:  GA1DBinaryStringGenome::FlipMutator
     crossover:  GA1DBinaryStringGenome::OnePointCrossover




GA2DBinaryStringGenome

The binary string genome is derived from the GABinaryString and GAGenome classes. It is a matrix of 1s and 0s whose width and height may be fixed or variable.

The genes in this genomes are bits. The alleles for each bit are 0 and 1.

see also: GABinaryString
see also: GAGenome
class hierarchy
class GA2DBinaryStringGenome : public GABinaryString, public GAGenome
constructors
GA2DBinaryStringGenome(unsigned int x, unsigned int y,
                       GAGenome::Evaluator objective = NULL,
                       void * userData = NULL)
GA2DBinaryStringGenome(const GA2DBinaryStringGenome &)
member function index
short gene(unsigned int x, unsigned int y) const
short gene(unsigned int x, unsigned int y, const short value)
  int width() const
  int width(int w)
  int height() const
  int height(int h)
  int resize(int x, int y)
  int resizeBehaviour(GADimension which) const 
  int resizeBehaviour(GADimension which,
                      unsigned int min, unsigned int max)
  int resizeBehaviour(unsigned int minx, unsigned int maxx, 
                      unsigned int miny, unsigned int maxy)
 void copy(const GA2DBinaryStringGenome &, 
           unsigned int xdest, unsigned int ydest,
           unsigned int xsrc, unsigned int ysrc, 
           unsigned int width, unsigned int height)
 void set(unsigned int, unsigned int, unsigned int, unsigned int)
 void unset(unsigned int, unsigned int, unsigned int, unsigned int)
member function descriptions
copy
Copy the specified bits from the designated genome. If you specify a range that is not represented by the genome, the range that you specified will be clipped to fit the genome.
gene
Set/Get the specified bit.
height
Set/Get the height of the bit string.
resize
Set the size of the genome to the specified dimensions.
resizeBehaviour
Set/Get the resize behavior. The min value specifies the minimum allowable length, the max value specifies the maximum allowable length. If min and max are equal, the genome is not resizable.

Use the resizeBehaviour and resize member functions to control the size of the genome. The default behavior is fixed size. Using the resizeBehaviour method you can specify minimum and maximum values for the size of the genome. If you specify minimum and maximum as the same values then fixed size is assumed. If you use the resize method to specify a size that is outside the bounds set earlier using resizeBehaviour, the bounds will be 'stretched' to accommodate the value you specify with resize. Conversely, if the values you specify with resizeBehaviour conflict with the genome's current size, the genome will be resized to accommodate the new values.

When resizeBehaviour is called with no arguments, it returns the maximum size if the genome is resizable, or GAGenome::FIXED_SIZE if the size is fixed.

set
unset
Set/Unset the bits in the specified range. If you specify a range that is not represented by the genome, the range that you specified will be clipped to fit the genome.
width
Set/Get the width of the bit string.
genetic operators for this class
GA2DBinaryStringGenome::UniformInitializer
GA2DBinaryStringGenome::SetInitializer
GA2DBinaryStringGenome::UnsetInitializer
GA2DBinaryStringGenome::FlipMutator
GA2DBinaryStringGenome::BitComparator
GA2DBinaryStringGenome::UniformCrossover
GA2DBinaryStringGenome::EvenOddCrossover
GA2DBinaryStringGenome::OnePointCrossover
default genetic operators
initialization:  GA2DBinaryStringGenome::UniformInitializer
    comparison:  GA2DBinaryStringGenome::BitComparator
      mutation:  GA2DBinaryStringGenome::FlipMutator
     crossover:  GA2DBinaryStringGenome::OnePointCrossover




GA3DBinaryStringGenome

The binary string genome is derived from the GABinaryString and GAGenome classes. It is a three-dimensional block of 1s and 0s whose width, height, and depth can be fixed or variable.

The genes in this genomes are bits. The alleles for each bit are 0 and 1.

see also: GABinaryString
see also: GAGenome
class hierarchy
class GA3DBinaryStringGenome : public GABinaryString, public GAGenome
constructors
GA3DBinaryStringGenome(unsigned int x, unsigned int y, unsigned int z,
                       GAGenome::Evaluator objective = NULL,
                       void * userData = NULL)
GA3DBinaryStringGenome(const GA3DBinaryStringGenome&)
member function index
short gene(unsigned int x, unsigned int y, unsigned int z) const
short gene(unsigned int x, unsigned int y, unsigned int z, short value)
  int width() const
  int width(int w)
  int height() const
  int height(int h)
  int depth() const
  int depth(int d)
  int resize(int x, int y, int z)
  int resizeBehaviour(GADimension which) const
  int resizeBehaviour(GADimension which,
                      unsigned int min, unsigned int max)
  int resizeBehaviour(unsigned int minx, unsigned int maxx, 
                      unsigned int miny, unsigned int maxy, 
                      unsigned int minz, unsigned int maxz)
 void copy(const GA3DBinaryStringGenome &, 
           unsigned int xdest, unsigned int ydest, unsigned int zdest,
           unsigned int xsrc, unsigned int ysrc, unsigned int zsrc,
           unsigned int width, unsigned int height, unsigned int depth);
 void set(unsigned int, unsigned int,
	  unsigned int, unsigned int,
	  unsigned int, unsigned int);
 void unset(unsigned int, unsigned int,
	    unsigned int, unsigned int,
	    unsigned int, unsigned int);
member function descriptions
copy
Copy the specified bits from the designated genome. If you specify a range that is not represented by the genome, the range that you specified will be clipped to fit the genome.
depth
Set/Get the depth of the bit string.
gene
Set/Get the specified bit.
height
Set/Get the height of the bit string.
resize
Set the size of the genome to the specified dimensions.
resizeBehaviour
Set/Get the resize behavior. The min value specifies the minimum allowable length, the max value specifies the maximum allowable length. If min and max are equal, the genome is not resizable.

Use the resizeBehaviour and resize member functions to control the size of the genome. The default behavior is fixed size. Using the resizeBehaviour method you can specify minimum and maximum values for the size of the genome. If you specify minimum and maximum as the same values then fixed size is assumed. If you use the resize method to specify a size that is outside the bounds set earlier using resizeBehaviour, the bounds will be 'stretched' to accommodate the value you specify with resize. Conversely, if the values you specify with resizeBehaviour conflict with the genome's current size, the genome will be resized to accommodate the new values.

When resizeBehaviour is called with no arguments, it returns the maximum size if the genome is resizable, or GAGenome::FIXED_SIZE if the size is fixed.

set
unset
Set/Unset the bits in the specified range. If you specify a range that is not represented by the genome, the range that you specified will be clipped to fit the genome.
width
Set/Get the width of the bit string.
genetic operators for this class
GA3DBinaryStringGenome::UniformInitializer
GA3DBinaryStringGenome::SetInitializer
GA3DBinaryStringGenome::UnsetInitializer
GA3DBinaryStringGenome::FlipMutator
GA3DBinaryStringGenome::BitComparator
GA3DBinaryStringGenome::UniformCrossover
GA3DBinaryStringGenome::EvenOddCrossover
GA3DBinaryStringGenome::OnePointCrossover
default genetic operators
initialization:  GA3DBinaryStringGenome::UniformInitializer
    comparison:  GA3DBinaryStringGenome::BitComparator
      mutation:  GA3DBinaryStringGenome::FlipMutator
     crossover:  GA3DBinaryStringGenome::OnePointCrossover




GA1DArrayGenome<T>

The 1D array genome is a generic, resizable array of objects. It is a template class derived from the GAGenome class as well as the GAArray<> class.

Each element in the array is a gene. The values of the genes are determines by the type of the genome. For example, an array of ints may have integer values whereas an array of doubles may have floating point values.

see also: GAArray
see also: GAGenome
class hierarchy
class GA1DArrayGenome<T> : public GAArray<T>, public GAGenome
constructors
GA1DArrayGenome(unsigned int length,
                GAGenome::Evaluator objective = NULL,
                void * userData = NULL)
GA1DArrayGenome(const GA1DArrayGenome<T> &)
member function index
const T & gene(unsigned int x=0) const
      T & gene(unsigned int x=0)
      T & gene(unsigned int x, const T& value)
const T & operator[](unsigned int x) const
      T & operator[](unsigned int x)
      int length() const
      int length(int l)
      int resize(int x)
      int resizeBehaviour() const
      int resizeBehaviour(unsigned int minx, unsigned int maxx)
     void copy(const GA1DArrayGenome<T>& original,
                unsigned int dest, unsigned int src, unsigned int length)
     void swap(unsigned int x1, unsigned int x2)
member function descriptions
copy
Copy the specified bits from the designated genome.
gene
Set/Get the specified element.
length
Set/Get the length.
resize
Set the length.
resizeBehaviour
Set/Get the resize behavior. The min value specifies the minimum allowable length, the max value specifies the maximum allowable length. If min and max are equal, the genome is not resizable.

Use the resizeBehaviour and resize member functions to control the size of the genome. The default behavior is fixed size. Using the resizeBehaviour method you can specify minimum and maximum values for the size of the genome. If you specify minimum and maximum as the same values then fixed size is assumed. If you use the resize method to specify a size that is outside the bounds set earlier using resizeBehaviour, the bounds will be 'stretched' to accommodate the value you specify with resize. Conversely, if the values you specify with resizeBehaviour conflict with the genome's current size, the genome will be resized to accommodate the new values.

When resizeBehaviour is called with no arguments, it returns the maximum size if the genome is resizable, or GAGenome::FIXED_SIZE if the size is fixed.

swap
Swap the specified elements.
genetic operators for this class
GA1DArrayGenome<>::SwapMutator
GA1DArrayGenome<>::ElementComparator
GA1DArrayGenome<>::UniformCrossover
GA1DArrayGenome<>::EvenOddCrossover
GA1DArrayGenome<>::OnePointCrossover
GA1DArrayGenome<>::TwoPointCrossover
GA1DArrayGenome<>::PartialMatchCrossover
GA1DArrayGenome<>::OrderCrossover
GA1DArrayGenome<>::CycleCrossover
default genetic operators
initialization:  GAGenome::NoInitializer
    comparison:  GA1DArrayGenome<>::ElementComparator
      mutation:  GA1DArrayGenome<>::SwapMutator
     crossover:  GA1DArrayGenome<>::OnePointCrossover




GA1DArrayAlleleGenome<T>

The one-dimensional array allele genome is derived from the one-dimensional array genome class. It shares the same behaviors, but adds the features of allele sets. The value assumed by each element in an array allele genome depends upon the allele set specified for that element. In the simplest case, you can create a single allele set which defines the possible values for any element in the array. More complicated examples can have a different allele set for each element in the array.

If you create the genome with a single allele set, the genome will have a length that you specify and the allele set will be used for the mapping of each element. If you create the genome using an array of allele sets, the genome will have a length equal to the number of allele sets in the array and each element of the array will be mapped using the corresponding allele set.

When you define an allele set for an array genome, the genome makes its own copy. Subsequent clones of this genome will refer to the original genome's allele set (allele sets do reference counting).

see also: GAArray
see also: GA1DArrayGenome
see also: GAAlleleSet
see also: GAAlleleSetArray
class hierarchy
class GA1DArrayAlleleGenome<T> : public GAArrayGenome<T>
constructors
GA1DArrayAlleleGenome(unsigned int length,
                      const GAAlleleSet<T>& alleleset,
                      GAGenome::Evaluator objective = NULL,
                      void * userData = NULL)
GA1DArrayAlleleGenome(const GAAlleleSetArray<T>& allelesets,
                      GAGenome::Evaluator objective = NULL,
                      void * userData = NULL)
GA1DArrayAlleleGenome(const GA1DArrayAlleleGenome<T>&)
member function index
const GAAlleleSet<T>& alleleset(unsigned int i = 0) const
member function descriptions
alleleset
Returns a reference to the allele set for the specified gene. If the genome was created using a single allele set, the allele set will be the same for every gene. If the genome was created using an allele set array, each gene may have a different allele set.
genetic operators for this class
GA1DArrayAlleleGenome<>::UniformInitializer
GA1DArrayAlleleGenome<>::OrderedInitializer
GA1DArrayAlleleGenome<>::FlipMutator
default genetic operators
initialization:  GA1DArrayAlleleGenome<>::UniformInitializer
    comparison:  GA1DArrayGenome<>::ElementComparator
      mutation:  GA1DArrayAlleleGenome<>::FlipMutator
     crossover:  GA1DArrayGenome<>::OnePointCrossover




GA2DArrayGenome<T>

The two-dimensional array genome is a generic, resizable array of objects. It is a template class derived from the GAGenome class as well as the GAArray<> class.

Each element in the array is a gene. The values of the genes are determines by the type of the genome. For example, an array of ints may have integer values whereas an array of doubles may have floating point values.

see also: GAArray
see also: GAGenome
class hierarchy
class GA2DArrayGenome<T> : public GAArray<T>, public GAGenome
constructors
GA2DArrayGenome(unsigned int width, unsigned int height,
                GAGenome::Evaluator objective = NULL,
                void * userData = NULL)
GA2DArrayGenome(const GA2DArrayGenome<T> &)
member function index
const T & gene(unsigned int x, unsigned int y) const
      T & gene(unsigned int x, unsigned int y)
      T & gene(unsigned int x, unsigned int y, const T& value)
      int width() const
      int width(int w)
      int height() const
      int height(int h)
      int resize(int x, int y)
      int resizeBehaviour(GADimension which) const
      int resizeBehaviour(GADimension which, 
                            unsigned int min, unsigned int max)
      int resizeBehaviour(unsigned int minx, unsigned int maxx, 
                            unsigned int miny, unsigned int maxy)
     void copy(const GA2DArrayGenome<T>& original,
                unsigned int xdest, unsigned int ydest,
                unsigned int xsrc, unsigned int ysrc,
                unsigned int width, unsigned int height)
     void swap(unsigned int x1, unsigned int y1,
                unsigned int x2, unsigned int y2)
member function descriptions
copy
Copy the specified bits from the designated genome.
gene
Set/Get the specified element.
height
Set/Get the height.
resize
Change the size to the specified dimensions.
resizeBehaviour
Set/Get the resize behavior. The min value specifies the minimum allowable length, the max value specifies the maximum allowable length. If min and max are equal, the genome is not resizable.

Use the resizeBehaviour and resize member functions to control the size of the genome. The default behavior is fixed size. Using the resizeBehaviour method you can specify minimum and maximum values for the size of the genome. If you specify minimum and maximum as the same values then fixed size is assumed. If you use the resize method to specify a size that is outside the bounds set earlier using resizeBehaviour, the bounds will be 'stretched' to accommodate the value you specify with resize. Conversely, if the values you specify with resizeBehaviour conflict with the genome's current size, the genome will be resized to accommodate the new values.

When resizeBehaviour is called with no arguments, it returns the maximum size if the genome is resizable, or GAGenome::FIXED_SIZE if the size is fixed.

The resizeBehaviour function works similarly to that of the 1D array genome. In this case, however, you must also specify for which dimension you are setting the resize behavior. When resizeBehaviour is called with no arguments, it returns the maximum size if the genome is resizable, or gaNoResize if the size is fixed.

swap
Swap the specified elements.
width
Set/Get the width.
genetic operators for this class
GA2DArrayGenome<>::SwapMutator
GA2DArrayGenome<>::ElementComparator
GA2DArrayGenome<>::UniformCrossover
GA2DArrayGenome<>::EvenOddCrossover
GA2DArrayGenome<>::OnePointCrossover
default genetic operators
initialization:  GAGenome::NoInitializer
    comparison:  GA2DArrayGenome<>::ElementComparator
      mutation:  GA2DArrayGenome<>::SwapMutator
     crossover:  GA2DArrayGenome<>::OnePointCrossover




GA2DArrayAlleleGenome<T>

The two-dimensional array allele genome is derived from the two-dimensional array genome class. It shares the same behaviors, but adds the features of allele sets. The value assumed by each element in an array allele genome depends upon the allele set specified for that element. In the simplest case, you can create a single allele set which defines the possible values for any element in the array. More complicated examples can have a different allele set for each element in the array.

The genome will have width and height that you specify and the allele set will be used for the mapping of each element. When you define an allele set for an array genome, the genome makes its own copy. Subsequent clones of this genome will refer to the original genome's allele set (allele sets do reference counting).

If you create a genome using an allele set array, the array of alleles will be mapped to the two dimensions in the order width-then-height.

see also: GAArray
see also: GA2DArrayGenome
see also: GAAlleleSet
see also: GAAlleleSetArray
class hierarchy
class GA1DArrayAlleleGenome<T> : public GAArrayGenome<T>
constructors
GA2DArrayAlleleGenome(unsigned int width, unsigned int height,
                      GAAlleleSet<T>& alleles,
                      GAGenome::Evaluator objective = NULL,
                      void * userData = NULL)
GA2DArrayAlleleGenome(unsigned int width, unsigned int height,
                      GAAlleleSetArray<T>& allelesets,
                      GAGenome::Evaluator objective = NULL,
                      void * userData = NULL)
GA2DArrayAlleleGenome(const GA2DArrayAlleleGenome<T> &)
member function index
const GAAlleleSet<T>& alleleset(unsigned int i = 0, unsigned int j = 0) const
member function descriptions
alleleset
Returns a reference to the allele set for the specified gene. If the genome was created using a single allele set, the allele set will be the same for every gene. If the genome was created using an allele set array, each gene may have a different allele set.
genetic operators for this class
GA2DArrayAlleleGenome<>::UniformInitializer
GA2DArrayAlleleGenome<>::FlipMutator
default genetic operators
initialization:  GA2DArrayAlleleGenome<>::UniformInitializer
    comparison:  GA2DArrayGenome<>::ElementComparator
      mutation:  GA2DArrayAlleleGenome<>::FlipMutator
     crossover:  GA2DArrayGenome<>::OnePointCrossover




GA3DArrayGenome<T>

The three-dimensional array genome is a generic, resizable array of objects. It is a template class derived from the GAGenome class as well as the GAArray<> class.

Each element in the array is a gene. The values of the genes are determines by the type of the genome. For example, an array of ints may have integer values whereas an array of doubles may have floating point values.

see also: GAArray
see also: GAGenome
class hierarchy
class GA3DArrayGenome<T> : public GAArray<T>, public GAGenome
constructors
GA3DArrayGenome(unsigned int width, unsigned int height, unsigned int depth,
                GAGenome::Evaluator objective = NULL,
                void * userData = NULL)
GA3DArrayGenome(const GA3DArrayGenome<T>&)
member function index
const T & gene(unsigned int x, unsigned int y, unsigned int z) const
      T & gene(unsigned int x, unsigned int y, unsigned int z)
      T & gene(unsigned int x, unsigned int y, unsigned int z, const T& value)
      int width() const
      int width(int w)
      int height() const
      int height(int h)
      int depth() const
      int depth(int d)
      int resize(int x, int y, int z)
      int resizeBehaviour(GADimension which) const
      int resizeBehaviour(GADimension which,
                            unsigned int min, unsigned int max)
      int resizeBehaviour(unsigned int minx, unsigned int maxx, 
                            unsigned int miny, unsigned int maxy,
                            unsigned int minz, unsigned int maxz)
     void copy(const GA3DArrayGenome<T>& original,
                unsigned int xdest, unsigned int ydest, unsigned int zdest,
                unsigned int xsrc, unsigned int ysrc, unsigned int zsrc,
                unsigned int width, unsigned int height, unsigned int depth)
     void swap(unsigned int x1, unsigned int y1, unsigned int z1,
                unsigned int x2, unsigned int y2, unsigned int z2)
member function descriptions
copy
Copy the specified bits from the designated genome.
depth
Set/Get the depth.
gene
Set/Get the specified element.
height
Set/Get the height.
resize
Change the size to the specified dimensions.
resizeBehaviour
Set/Get the resize behavior. The min value specifies the minimum allowable length, the max value specifies the maximum allowable length. If min and max are equal, the genome is not resizable.

Use the resizeBehaviour and resize member functions to control the size of the genome. The default behavior is fixed size. Using the resizeBehaviour method you can specify minimum and maximum values for the size of the genome. If you specify minimum and maximum as the same values then fixed size is assumed. If you use the resize method to specify a size that is outside the bounds set earlier using resizeBehaviour, the bounds will be 'stretched' to accommodate the value you specify with resize. Conversely, if the values you specify with resizeBehaviour conflict with the genome's current size, the genome will be resized to accommodate the new values.

When resizeBehaviour is called with no arguments, it returns the maximum size if the genome is resizable, or GAGenome::FIXED_SIZE if the size is fixed.

The resizeBehaviour function works similarly to that of the 1D array genome. In this case, however, you must also specify for which dimension you are setting the resize behavior. When resizeBehaviour is called with no arguments, it returns the maximum size if the genome is resizable, or gaNoResize if the size is fixed.

swap
Swap the specified elements.
width
Set/Get the width.
genetic operators for this class
GA3DArrayGenome<>::SwapMutator
GA3DArrayGenome<>::ElementComparator
GA3DArrayGenome<>::UniformCrossover
GA3DArrayGenome<>::EvenOddCrossover
GA3DArrayGenome<>::OnePointCrossover
default genetic operators
initialization:  GAGenome::NoInitializer
    comparison:  GA3DArrayGenome<>::ElementComparator
      mutation:  GA3DArrayGenome<>::SwapMutator
     crossover:  GA3DArrayGenome<>::OnePointCrossover




GA3DArrayAlleleGenome<T>

The three-dimensional array allele genome is derived from the three-dimensional array genome class. It shares the same behaviors, but adds the features of allele sets. The value assumed by each element in an array allele genome depends upon the allele set specified for that element. In the simplest case, you can create a single allele set which defines the possible values for any element in the array. More complicated examples can have a different allele set for each element in the array.

The genome will have width, height, and depth that you specify and the allele set will be used for the mapping of each element. When you define an allele set for an array genome, the genome makes its own copy. Subsequent clones of this genome will refer to the original genome's allele set (allele sets do reference counting).

If you create a genome using an allele set array, the array of alleles will be mapped to the three dimensions in the order width-then-height-then-depth.

see also: GAArray
see also: GA3DArrayGenome
see also: GAAlleleSet
see also: GAAlleleSetArray
class hierarchy
class GA1DArrayAlleleGenome<T> : public GAArrayGenome<T>
constructors
GA3DArrayAlleleGenome(unsigned int width, unsigned int height, unsigned int depth,
                      GAAlleleSet<T>& alleles,
                      GAGenome::Evaluator objective = NULL,
                      void * userData = NULL)
GA3DArrayAlleleGenome(unsigned int width, unsigned int height, unsigned int depth,
                      GAAlleleSet<T>& alleles,
                      GAGenome::Evaluator objective = NULL,
                      void * userData = NULL)
GA3DArrayAlleleGenome(const GA3DArrayAlleleGenome<T> &)
member function index
const GAAlleleSet<T>& alleleset(unsigned int i = 0,
                                 unsigned int j = 0,
                                 unsigned int k = 0) const
member function descriptions
alleleset
Returns a reference to the allele set for the specified gene. If the genome was created using a single allele set, the allele set will be the same for every gene. If the genome was created using an allele set array, each gene may have a different allele set.
genetic operators for this class
GA3DArrayAlleleGenome<>::UniformInitializer
GA3DArrayAlleleGenome<>::FlipMutator
default genetic operators
initialization:  GA3DArrayAlleleGenome<>::UniformInitializer
    comparison:  GA3DArrayGenome<>::ElementComparator
      mutation:  GA3DArrayAlleleGenome<>::FlipMutator
     crossover:  GA3DArrayGenome<>::OnePointCrossover




GABin2DecPhenotype

The binary-to-decimal phenotype defines the mapping from binary string to decimal values. A mapping for a single binary-to-decimal conversion consists of a range of decimal values and a number of bits. For example, a map of 8 bits and range of [0,255] would use 8 bits to represent the numbers from 0 to 255, inclusive.

This object does reference counting in order to minimize the memory overhead imposed by instantiating binary-to-decimal mappings.

constructors
GABin2DecPhenotype()
GABin2DecPhenotype(const GABin2DecPhenotype&)
member function index
 void add(unsigned int nbits, float min, float max)
 void remove(unsigned int which)
  int size() const
  int nPhenotypes() const
float min(unsigned int which) const
float max(unsigned int which) const
  int length(unsigned int which) const
  int offset(unsigned int which) const

 void link(GABin2DecPhenotype&)
 void unlink()
member function descriptions
add
Create a mapping that tells the phenotype that nbits should be used to represent a floating point number from min to max, inclusive.
link
unlink
The phenotype object does reference counting to reduce the number of instantiated objects. Use the link member to make a phenotype object refer to another. Use the unlink member to remove the connection. When you unlink, the phenotype makes its own copy of the mapping information.
length
Returns the number of bits required for the specified mapping.
max
Returns the maximum decimal value for the specified mapping.
min
Returns the minimum decimal value for the specified mapping.
offset
Returns the offset (in bits) for the specified mapping.
remove
Removes a single binary-to-decimal from the phenotype.
size
Returns the number of bits that the set of mappings requires for converting a decimal value to binary and back again.




GAAlleleSet<T>

The allele set class is a container for the different values that a gene may assume. It can contain objects of any type as long as the object has the =, ==, and != operators defined.

Allele sets may be enumerated, bounded, or bounded with discretization. For example, an integer allele set may be defined as {1,3,5,2,99,-53} (an enumerated set). A bounded float set may be defined such as [2,743) (the set of numbers from 2, inclusive, to 743, exclusive). A bounded, discretized set may defined such as [4.5,7.05](0.05) (the set of numbers from 4.5 to 7.5, inclusive, with increment of 0.05).

If you call the allele member function with no argument, the allele set picks randomly from the alleles it contains and returns one of them.

constructors
GAAlleleSet()
GAAlleleSet(unsigned int n, const T a[])
GAAlleleSet(const T& lower, const T& upper, 
	    GAAllele::BoundType lowerbound=GAAllele::INCLUSIVE, 
	    GAAllele::BoundType upperbound=GAAllele::INCLUSIVE)
GAAlleleSet(const T& lower, const T& upper, const T& increment,
	    GAAllele::BoundType lowerbound=GAAllele::INCLUSIVE, 
	    GAAllele::BoundType upperbound=GAAllele::INCLUSIVE)
GAAlleleSet(const GAAlleleSet<T>& set)
member function index
   GAAlleleSet<T> * clone() const

                  T add(const T& allele)
                  T remove(T& allele)
                  T allele() const
                  T allele(unsigned int i)
                int size() const

                  T lower() const
                  T upper() const
                  T inc() const
GAAllele::BoundType lowerBoundType() const
GAAllele::BoundType upperBoundType() const
     GAAllele::Type type() const

               void link(GAAlleleSet<T>&)
               void unlink()
member function descriptions
add
remove
Add/Remove the indicated allele from the set. This method works only for enumerated allele sets. Both functions return zero if the operation was successful, non-zero status otherwise.
lower
upper
Returns the lower/upper bounds on the allele set. If the allele set is enumerated, lower returns the first element of the set and upper returns the last element of the set.
inc
Returns the increment of the allele set. If the set is not discretized, the first element or lower bounds of the set is returned.
lowerBoundType
upperBoundType
Returns GAAllele::INCLUSIVE or GAAllele::EXCLUSIVE to indicate the type of bound on the limits of the allele set. If no bounds have been defined, these method return GAAllele::NONE.
link
unlink
The alleleset object does reference counting to reduce the number of instantiated objects. Use the link member to make an alleleset object refer to the data in another. Use the unlink member to remove the connection. When you unlink, the alleleset makes its own copy of the set data.
size
Returns the number of elements in the allele set. This member is meaningful only for the enumerated allele set.
type
Returns GAAllele::ENUMERATED, GAAllele::BOUNDED, or GAAllele::DISCRETIZED to indicate the type of allele set that has been defined. The type of the allele set is specified by the creator used to instantiate the allele set.




GAAlleleSetArray<T>

The GAAlleleSetArray is a container object with an array of allele sets.
constructors
GAAlleleSetArray()
GAAlleleSetArray(const GAAlleleSet<T>&)
GAAlleleSetArray(const GAAlleleSetArray<T>&)
member function index
                  int size() const
const GAAlleleSet<T>& set(unsigned int i) const
                  int add(const GAAlleleSet<T>& s)
                  int add(unsigned int n, const T a[])
                  int add(const T& lower, const T& upper,
	                  GAAllele::BoundType lb=GAAllele::INCLUSIVE,
	                  GAAllele::BoundType ub=GAAllele::INCLUSIVE)
                  int add(const T& lower, const T& upper, const T& increment,
	                  GAAllele::BoundType lb=GAAllele::INCLUSIVE, 
	                  GAAllele::BoundType ub=GAAllele::INCLUSIVE)
                  int remove(unsigned int)
member function descriptions
add
Use the add members to append an allele set to the end of the array. Each of the overloaded add members invokes a corresponding allele set creator, so you can use the appropriate add member for your particular allele set application.
remove
Remove the indicated allele set from the array. Returns zero if successful, non-zero otherwise.
size
Returns the number of allele sets in the array.




GAStatistics

The statistics object contains information about the current state of the genetic algorithm objects. Every genetic algorithm contains a statistics object.

The statistics object defines the following enumerated constants for use by the selectScores member. They can be bitwise-ORed to specify desired combinations of components. Use the class name to refer to the values, for example GAStatistics::Mean | GAStatistics::Deviation

typedefs and constants
enum { NoScores,
       Mean, Maximum, Minimum, Deviation,
       Diversity,
       AllScores }
constructors
GAStatistics()
GAStatistics(const GAStatistics&)
member function index
     void copy(const GAStatistics &);

    float online() const
    float offlineMax() const
    float offlineMin() const
    float initial(ScoreID w=Maximum) const
    float current(ScoreID w=Maximum) const
    float maxEver() const
    float minEver() const

      int generation() const
    float convergence() const
      int selections() const
      int crossovers() const
      int mutations() const
      int replacements() const

      int nConvergence(unsigned int)
      int nConvergence() const
      int nBestGenomes(const GAGenome&, unsigned int)
      int nBestGenomes() const
      int scoreFrequency(unsigned int x)
      int scoreFrequency() const
      int flushFrequency(unsigned int x)
      int flushFrequency() const
    char* scoreFilename(const char *filename)
    char* scoreFilename() const
      int selectScores(int whichScores)
      int selectScores() const
GABoolean recordDiversity(GABoolean flag)
GABoolean recordDiversity() const
     void flushScores()

     void update(const GAPopulation& pop)
     void reset(const GAPopulation& pop)

const GAPopulation& bestPopulation() const 
    const GAGenome& bestIndividual(unsigned int n=0) const

      int scores(const char* filename, ScoreID which=NoScores)
      int scores(ostream& os, ScoreID which=NoScores)
      int write(const char* filename) const
      int write(ostream& os) const;

friend ostream& operator<<(ostream&, const GAStatistics&)
member function descriptions
bestIndividual
This function returns a reference to the best individual encountered by the genetic algorithm.
bestPopulation
This function returns a reference to a population containing the best individuals encountered by the genetic algorithm. The size of this population is specified using the nBestGenomes member function.
convergence
Returns the current convergence. Here convergence means the ratio of the nth previous best-of-generation to the current best-of-generation.
crossovers
Returns the number of crossovers that have occurred since initialization.
current
Returns the specified score from the current population.
flushFrequency
Set/Get the frequency at which the generational scores should be flushed to disk. A score frequency of 100 means that at every 100th recorded score the scores buffer will be appended to the scores file.
flushScores
Force a flush of the scores buffer to the score file.
generation
Returns the current generation number.
initial
Returns the specified score from the initial population.
maxEver
Returns the maximum score ever encountered.
minEver
Returns the minimum score ever encountered.
mutations
Returns the number of mutations that have occurred since initialization.
nBestGenomes
Set/Get the number of unique best genomes to keep.
nConvergence
Set/Get the number of generations to use for the convergence measure. A value of 10 means the best-of-generation from 10 generations previous will be used for the convergence test.
offlineMax
Returns the average of the maximum scores.
offlineMin
Returns the average of the minimum scores.
online
Returns the average of all scores.
recordDiversity
This boolean option determines whether or not the diversity of the population will be calculated each generation. By default, this option is set to false.
replacements
Returns the number of replacements that have occurred since initialization.
reset
Reset the contents of the statistics object using the contents of the specified population.
scoreFilename
Set the name of the file to which the scores should be output. If the filename is set to nil, the scores will not be written to disk. The default filename is "generations.dat".
scoreFrequency
Set/Get the frequency at which the generational scores should be recorded. A score frequency of 1 means the scores will be recorded each generation. The default depends on the type of genetic algorithm that is being used.
scores
Print the generational scores to the specified stream. Output is tab-delimited with each line containing the generation number and the specified scores. You can specify which score you would like by logically ORing one of the score identifiers listed above. The order of the tab-delimited scores is as follows:
generation  TAB  mean  TAB  max  TAB  min  TAB deviation  TAB  diversity NEWLINE
selections
Returns the number of selections that have occurred since initialization.
selectScores
This function is used to specify which scores should be saved to disk. The argument is the logical OR of the following values: Mean, Maximum, Minimum, Deviation, Diversity (all defined in the scope of the GAStatistics object). To record all of the scores, pass GAStatistics::AllScores.
update
Update the contents of the statistics object to reflect the state of the specified population.




GAParameterList

The parameter list object contains information about how genetic algorithms should behave. Each parameter list contains an array of parameters. Each parameter is a name-value pair, where the name is a string (e.g. "number_of_generations") and the value is an int, float, double, char, string, boolean, or pointer.

Each parameter is uniquely identified by a pair of names: the full name and the short name. Associated with the names is a value. Each parameter also has a type from the enumerated list of types shown above. The GAParameter object automatically does type coercion of the pointer that is passed to it based upon the type that is passed to it upon its creation. The type cannot be changed once the parameter has been created.

typedefs and constants
  enum GAParameter::Type {BOOLEAN, CHAR, STRING, INT, FLOAT, DOUBLE, POINTER};
constructors
GAParameter(const char* fn, const char* sn, Type tp, const void* v)
GAParameter(const GAParameter& orig)
member function index
          void copy(const GAParameter&)
         char* fullname() const
         char* shrtname() const
   const void* value() const 
   const void* value(const void* v) 
          Type type() const
constructors
GAParameterList()
GAParameterList(const GAParameterList&)
member function index
         int size() const
         int get(const char*, void*) const
         int set(const char*, const void*)
         int set(const char* s, int v)
         int set(const char* s, unsigned int v)
         int set(const char* s, char v)
         int set(const char* s, char* v)
         int set(const char* s, double v)
         int add(const char*, const char*, GAParameter::Type, const void*)
         int remove();
GAParameter& operator[](unsigned int i) const
GAParameter& next()
GAParameter& prev()
GAParameter& current() const
GAParameter& first()
GAParameter& last()
GAParameter* operator()(const char* name)
         int parse(int& argc, char **argv, GABoolean flag = gaFalse)

         int write(const char* filename) const
         int write(ostream& os) const
         int read(const char* filename)
         int read(istream& is)

friend ostream& operator<<(ostream& os, const GAParameterList& plist)
friend istream& operator>>(istream& is, GAParameterList& plist)
member function descriptions
add
Add a parameter with specified name, type, and default value to the parameter list. This becomes the current parameter.
current
Return a reference to the current parameter in the list.
first
Return a reference to the first parameter in the list. This becomes the current parameter.
get
Fills the contents of the space pointed to by ptr with the current value of the named parameter. Returns 0 if the parameter was found, non-zero otherwise.
last
Return a reference to the last parameter in the list. This becomes the current parameter.
next
Return a reference to the next parameter in the list. This becomes the current parameter.
parse
Parse an argument list (in command-line format) for recognized name-value pairs. If you pass gaTrue as the third argument then this method will post warnings about names that it does not recognize.
prev
Return a reference to the next parameter in the list. This becomes the current parameter.
read
Read a parameter list from the specified file or stream.
set
Set the named parameter to the specified value. Returns 0 if the paramter was found and successfully set, non-zero otherwise. You can use either the full or short name to specify a parameter.
size
Returns the number of parameters in the parameter list.
remove
Remove the current parameter from the parameter list.
write
Write the parameter list to the specified file or stream.




GAPopulation

The population object is a container for the genomes. It also contains population statistics such as average, maximum, and minimum genome objective scores. Each population contains a scaling object that is used to determine the fitness of its genomes. The population also contains a function used for selecting individuals from the population.

Whenever possible, the population caches the statistics. This means that the first call to one of the statistics members will be slower than subsequent calls.

You can customize the initialization, evaluation, and sort methods. Use the appropriate member function. Your customized functions must have the appropriate signature.

The default scaling scheme is linear scaling. The default evaluator invokes the objective function for each genome. The default selector is roulette wheel and uses the scaled (fitness) scores for its selections.

typedefs and constants
     void (*GAPopulation::Initializer)(GAPopulation &)
     void (*GAPopulation::Evaluator)(GAPopulation &)

  enum SortBasis { RAW, SCALED };
  enum SortOrder { LOW_IS_BEST, HIGH_IS_BEST };
enum Replacement { BEST = -1, WORST = -2, RANDOM = -3 };
constructors
GAPopulation()
GAPopulation(const GAGenome&, unsigned int popsize = gaDefPopSize)
GAPopulation(const GAPopulation&)
member function index
  GAPopulation * clone() const
            void copy(const GAPopulation&)

             int size(unsigned int popsize)
             int size() const

           float sum() const
           float ave() const
           float var() const
           float dev() const
           float max() const
           float min() const
           float div() const
           float div(unsigned int i, unsigned int j) const

           float fitsum() const
           float fitave() const
           float fitmax() const
           float fitmin() const
           float fitvar() const
           float fitdev() const
           float psum(unsigned int i) const

             int nevals() const

            void touch() 
            void statistics(GABoolean flag = gaFalse) const;
            void diversity(GABoolean flag = gaFalse) const;

              void prepselect(GABoolean flag = gaFalse) const;
         GAGenome& select()
GASelectionScheme& selector() const
GASelectionScheme& selector(const GASelectionScheme&)

              void scale(GABoolean flag = gaFalse) const;
  GAScalingScheme& scaling() const
  GAScalingScheme& scaling(const GAScalingScheme&)

              void sort(GABoolean flag = gaFalse, SortBasis basis = RAW) const;
         SortOrder order() const
         SortOrder order(SortOrder flag)

                     void evaluate(GABoolean flag = gaFalse) const
  GAPopulation::Evaluator evaluator(GAPopulation::Evaluator func)
  GAPopulation::Evaluator evaluator(GAPopulation::Evaluator func)

                     void initialize()
GAPopulation::Initializer initializer(GAPopulation::Initializer func)
GAPopulation::Initializer initializer(GAPopulation::Initializer func)

GAGeneticAlgorithm * geneticAlgorithm() const
GAGeneticAlgorithm * geneticAlgorithm(GA&)
              void * userData() const
              void * userData(void * u)
        GAEvalData * evalData() const
        GAEvalData * evalData(const GAEvalData&)

      GAGenome& individual(unsigned int x, SortBasis basis = RAW) const
      GAGenome& best(unsigned int i = 0, SortBasis basis = RAW) const
      GAGenome& worst(unsigned int i = 0, SortBasis basis = RAW) const

      GAGenome * add(GAGenome *)
      GAGenome * add(const GAGenome&)
      GAGenome * remove(unsigned int i, SortBasis basis = RAW)
      GAGenome * remove(GAGenome *)
      GAGenome * replace(GAGenome *, int which = gaPopReplaceRandom, SortBasis basis = RAW)
      GAGenome * replace(GAGenome *, GAGenome *)
            void destroy(int w = WORST, SortBasis basis = RAW)

    virtual void read(istream &)
    virtual void write(ostream &) const

friend ostream& operator<<(ostream &, const GAPopulation &)
friend istream& operator>>(istream &, GAPopulation &)
member function descriptions
add
Add the specified individual to the population. If you call this method with a reference to a genome, the population will clone the genome. If you call this method with a pointer to a genome, the population will use the genome pointed to by the pointer. From then on the population is responsible for deleting the genome.
ave
Returns the average of the objective scores.
best
Returns a reference to the best individual in the population. Use the SortBasis flag to specify whether you want the best in terms of raw objective score or scaled (fitness) score.
destroy
Remove the specified individual from the population and free the memory used by that individual. Use the SortBasis flag to specify whether to use raw objective score or scaled (fitness) score when determining which genome to destroy.
dev
Returns the standard deviation of the objective scores.
div
Returns the diversity of the population. Diversity is a number between 0 and 1 where 1 indicates that each individual is completely different than every other individual. If you specify two indices, this member function returns the diversity of the specified individuals (it invokes the comparison function for those individuals).
evalData
Set/Get the evaluation data for the population. This object is unrelated to any evaluation data objects used by the genomes in the population.
evaluate
Evaluate the population using the method set by the evaluator function. The default evaluator simply calls the evaluate member of each genome in the population. If you call this function with gaTrue then the population performs the evaluation even if it has already cached the evaluation results.
evaluator
Specifies which function to use to evaluate the population. The specified function must have the proper signature.
fitave
Returns the average of the fitness scores.
fitdev
Returns the standard deviation of the fitness scores.
fitmax
Returns the maximum fitness score.
fitmin
Returns the minimum fitness score.
fitsum
Returns the sum of the fitness scores.
fitvar
Returns the variance of the fitness scores.
geneticAlgorithm
Set/Get the genetic algorithm that 'owns' this population. A return value of nil indicates that the population is owned by no genetic algorithm.
individual
Returns a reference to the specified individual. Indices for individuals in the population start at 0 and go to size()-1. the 0th individual is the best individual when the population has been sorted. Use the SortBasis flag to specify whether you want the ith individual based upon the raw objective score or scaled (fitness) score.
initialize
Initialize the population using the method set by initializer. The default initializer simply calls the initialize method of each genome in the population.
initializer
Specifies which function to use to initialize the population. The specified function must have the proper signature.
max
Returns the maximum objective score in the population.
min
Returns the minimum objective score in the population.
order
Set/Get the sort order. A population may be sorted in two ways, highest-score-is-best or lowest-score-is-best.
prepselect
The function calls the selector's update method. It is typically called by the population before it does a selection.
psum
Returns the partial sum of the ith fitness score in the array of (sorted) fitness scores.
remove
Remove the specified individual from the population. The genome to be replaced can be specified by either an index or by pointer. This function returns a pointer to the genome that was removed from the population. The caller is responsible for the memory used by the returned genome. Use the SortBasis flag to specify whether to use raw objective score or scaled (fitness) score when determining which genome to remove.
replace
Replace the specified individual with the first argument. The genome to be replaced can be specified by either an index or by pointer. This function returns a pointer to the genome that was replaced. If no genome was replaced or the specified index or pointer is bogus, it returns nil. Use the SortBasis flag to specify whether to use raw objective score or scaled (fitness) score when determining which genome to replace.
scale
Scale the raw (objective) scores in the population using the scaling method. If you call this function with gaTrue then the scaled scores are recalculated even if the population has already cached them.
scaling
Set/Get the scaling method for this population.
select
Returns a reference to a genome from the population using the selection scheme associated with the population.
selector
Set/Get the selection method for this population.
size
Set/Get the number of individuals in the population. If you resize to a larger size, the new individuals will be initialized but not evaluated. If you resize to a smaller size, the best individuals will be kept.
sort
Sort the individuals in the population. Individuals may be sorted based upon their raw or scaled scores.
statistics
Calculate the population statistics. This method is automatically invoked whenever any of the population statistics are requested. If you call this function with gaTrue then the statistics are recalculated even if the population has already cached them.
sum
Returns the sum of the objective scores.
touch
The population object remembers its state so that it does not execute the evaluate or sort methods unless its state has been changed. If you want to force the population to execute any of its methods the next time they are invoked, invoke this method.
userData
Set/Get the user data pointer for the population. You can use the user data member to store a pointer to any object.
var
Returns the variance of the objective scores.
worst
Returns a reference to the worst individual in the population. Use the SortBasis flag to specify whether you want the worst in terms of raw objective score or scaled (fitness) score.




GAScalingScheme

The scaling object is embedded in the population object. This object keeps track of the fitness scores (not the objective scores) of each individual in the population.

The base scaling object is not instantiable. The genomes that it returns are the genomes in the population to which it is linked; it does not make its own copies.

For details about how to write your own scaling scheme, see the customizations page.

constructors
GAScalingScheme()
GAScalingScheme(const GAScalingScheme& s)
member function index
virtual GAScalingScheme * clone() const
             virtual void copy(const GAScalingScheme &)
             virtual void evaluate(const GAPopulation & p)
built-in scaling schemes

GAlib contains a number of instantiable scaling objects derived from the base class. Here are the constructors for these scaling schemes:

GANoScaling()
The fitness scores are identical to the objective scores. No scaling takes place.

GALinearScaling(float c = gaDefLinearScalingMultiplier)
The fitness scores are derived from the objective scores using the linear scaling method described in Goldberg's book. You can specify the scaling coefficient. Negative objective scores are not allowed with this method. Objective scores are converted to fitness scores using the relation
       f = a * obj + b
       
where a and b are calculated based upon the objective scores of the individuals in the population as described in Goldberg's book.

GASigmaTruncationScaling(float c = gaDefSigmaTruncationMultiplier)
Use this scaling method if your objective scores will be negative. It scales based on the variation from the population average and truncates arbitrarily at 0. The mapping from objective to fitness score for each individual is given by
       f = obj - (obj_ave - c * obj_dev)
       

GAPowerLawScaling(int k = gaDefPowerScalingFactor)
Power law scaling maps objective scores to fitness scores using an exponential relationship defined as
       f = obj ^ k
       

GASharing(GAGenomeComparator func = 0, float cutoff = gaDefSharingCutoff, float alpha = 1)
This scaling method is used to do speciation. The fitness score is derived from its objective score by comparing the individual against the other individuals in the population. If there are other similar individuals then the fitness is derated. The distance function is used to specify how similar to each other two individuals are. A distance function must return a value of 0 or higher, where 0 means that the two individuals are identical (no diversity). For a given individual,

       f = obj / summation( s( d(j)))         for all j = [0,popsize]

                   /
                  |   1 - (d(j) / sigma) ^ alpha        d(j) < sigma
       s(d(j)) =  |
                  |   0                                 d(j) >= sigma
                   \

       d(j) = distance function with respect to individual j
       

The default sharing object uses the triangular sharing function described in Goldberg's book. You can specify the cutoff value (sigma in Goldberg's book) using the sigma member function. The curvature of the sharing function is controlled by the alpha value. When alpha is 1.0 the sharing function is a straight line (triangular sharing). If you specify a comparator, that function will be used as the distance function for all comparisons. If you do not specify a comparator, the sharing object will use the default comparator of each genome.

Notice that the sharing scaling differs depending on whether the objective is to maximized or minimized. If the goal is to maximize the objective score, the raw scores will be divided by the sharing factor. If the goal is to minimize the objective score, the raw scores will be multiplied by the sharing factor. You can explicitly tell the sharing object to do minimize- or maximize-based scaling by using the minimaxi member function. By default, it uses the min/max settings of the genetic algorithm that is using it (based on information in the population with which the sharing object is associated). If the scaling object is associated with a population that has been created independently of any genetic algorithm object, the sharing object will use the population's order to decide whether to multiply or divide to do its scaling.





GASelectionScheme

Selection schemes are used to pick genomes from a population for mating. The GASelectionScheme object defines the basic selector behavior. It is an abstract class and cannot be instantiated. Each selector object may be linked to a population from which it will make its selections. The select member returns a reference to a single genome. A selector may operate on the scaled objective scores or the raw objective scores. Default behavior is to operate on the scaled (fitness) scores.

For details about how to write your own selection scheme, see the customizations page.

typedefs and constants
  enum { RAW, SCALED };
constructors
  GASelectionScheme(int which = SCALED)
  GASelectionScheme(const GASelectionScheme&)
member function index
virtual GASelectionScheme* clone() const;
              virtual void copy(const GASelectionScheme& orig)
              virtual void assign(GAPopulation& pop)
              virtual void update()
         virtual GAGenome& select() const;
built-in scaling schemes

GAlib contains a number of instantiable scaling objects derived from the base class. Here are the constructors for these scaling schemes:

GARankSelector
The rank selector picks the best member of the population every time.

GARouletteWheelSelector
This selection method picks an individual based on the magnitude of the fitness score relative to the rest of the population. The higher the score, the more likely an individual will be selected. Any individual has a probability p of being chosen where p is equal to the fitness of the individual divided by the sum of the fitnesses of each individual in the population.

GATournamentSelector
The tournament selector uses the roulette wheel method to select two individuals then picks the one with the higher score. The tournament selector typically chooses higher valued individuals more often than the RouletteWheelSelector.

GADSSelector
The deterministic sampling selector (DS) uses a two-staged selection procedure. In the first stage, each individual's expected representation is calculated. A temporary population is filled using the individuals with the highest expected numbers. Any remaining positions are filled by first sorting the original individuals according to the decimal part of their expected representation, then selecting those highest in the list. The second stage of selection is uniform random selection from the temporary population.

GASRSSelector
The stochastic remainder sampling selector (SRS) uses a two-staged selection procedure. In the first stage, each individual's expected representation is calculated. A temporary population is filled using the individuals with the highest expected numbers. Any fractional expected representations are used to give the individual more likeliehood of filling a space. For example, an individual with e of 1.4 will have 1 position then a 40% chance of a second position. The second stage of selection is uniform random selection from the temporary population.

GAUniformSelector
The stochastic uniform sampling selector picks randomly from the population. Any individual in the population has a probability p of being chosen where p is equal to 1 divided by the population size.





GABinaryString

The binary string object is a simple implementation of a string of bits. Each bit is represented by a single word of memory (no fancy bit-munging happens here). The binary string class defines the following member functions. Binary strings are resizable.

constructors
GABinaryString(unsigned int length)
GABinaryString(const GABinaryString&)
member function index
 void copy(const GABinaryString&)
  int resize(unsigned int)
  int size() const

short bit(unsigned int a) const
short bit(unsigned int a, short val)
  int equal(const GABinaryString& b,
	    unsigned int dest, unsigned int src, unsigned int length) const
 void copy(const GABinaryString& orig,
           unsigned int dest, unsigned int src, unsigned int length)
 void move(unsigned int dest, unsigned int src, unsigned int length)
 void set(unsigned int a, unsigned int length)
 void unset(unsigned int a, unsigned int length)
 void randomize(unsigned int a, unsigned int length)
member function descriptions
copy
Makes an exact copy of the specified string. If invoked with a range of bits then copies the specified range of bits.
bit
Set/Get the specified bit.
equal
Returns 1 if the specified range of bits are equal, 0 otherwise.
move
Move length bits starting at src to dest.
set/unset
Set/Unset length bits starting at a
size
resize
Set/Get the length of the bit string.
randomize
Set to random values length bits starting at a




GAArray<T>

The GAArray<T> object is defined for your convenience so that you do not have to create your own array object. It is a template-ized container class whose elements can contain objects of any type. The 1-, 2-, and 3-dimensional arrays used in GAlib are all based upon this single-dimensional array object. This object is defined in the file arraytmpl.h.

array The GAArray object
The squares are elements in the array. Arrays are 1 dimensional, but derived classes can have 2 or more dimensions. Each element contains a user-specified object.

Any object in the array must have the following methods defined and publicly available:

  • copy constructor
  • operator =
  • operator ==
  • operator !=

The elements in an array are indexed starting with 0 (the first element in the array is element number 0). The last element in array with n elements is element n-1.

constructors
GAArray(unsigned int)
GAArray(const GAArray<T>&)
member function index
GAArray<T> & operator=(const GAArray<T>& orig)
GAArray<T> & operator=(const T array [])
GAArray<T> * clone()
   const T & operator[](unsigned int i) const
         T & operator[](unsigned int i)
        void copy(const GAArray<T>& orig)
        void copy(const GAArray<T>& orig, unsigned int dest,
	          unsigned int src, unsigned int length)
        void move(unsigned int dest,
	          unsigned int src, unsigned int length)
        void swap(unsigned int i, unsigned int j)
         int size() const
         int size(unsigned int n)
         int equal(const GAArray<T>& b,
	           unsigned int dest, unsigned int src,
	           unsigned int length) const

         int operator==(const GAArray<T>& a, const GAArray<T>& b)
         int operator!=(const GAArray<T>& a, const GAArray<T>& b)
member function descriptions
clone
Return a pointer to an exact duplicate of the original array. The caller is responsible for the memory allocated by the call to this function.
copy
Duplicate the specified array or part of the specified array. If duplicating a part of the specified array, length elements starting at position src in the original are copied into position dest in the copy. If there is not enough space in the copy, the extra elements are not copied.
equal
Return 1 if the specified portion of the two arrays is identical, return 0 otherwise.
move
Move the number of elements specified with length from position src to position dest.
operator[]
Return a reference to the contents of the ith element of the array.
size
Return the number of elements in the array.
swap
Swap the contents of element i with the contents of element j.




GAList<T> and GAListIter<T>

The GAList<T> object is defined for your convenience so that you do not have to create your own list object. It is a template-ized container class whose nodes can contain objects of any type. The GAList<T> object is circular and doubly-linked. A list iterator object is also defined to be used when moving around the list to keep track of the current, next, previous, or whichever node. Iterators do not change the state of the list.

list The GAList object
The circles are nodes in the list. Each node contains a user-specified object; the initialization method determines the size of the list and the contents of each node. The list is circular and doubly linked.

The template-ized GAList<T> is derived from a generic list base class called GAListBASE. The template list is defined in listtmpl.h, the list base class is defined in listbase.h

Any object used in the nodes must have the following methods defined and publicly available:

  • copy constructor
  • operator =
  • operator ==
  • operator !=

Each list object contains an iterator. The list's traversal member functions (next, prev, etc) simply call the member functions on the internal iterator. You can also instantiate iterators external to the list object so that you can traverse the list without modifying its state.

The list base class defines constants for specifying where insertions should take place (these are relative to the node to which the iterator is currently pointing).

Nodes in the list are numbered from 0 to 1 less than the list size. The head node is node 0.

When you do an insertion, the list makes a copy of the specified object (allocating space for it in the process). The internal iterator is left pointing to the node which was just inserted. The insertion function uses the copy constructor member to do this, so the objects in your list must have a copy constructor defined. The new node is inserted relative to the current location of the list's internal iterator. Use the where flag to determine whether the new node will be inserted before or after the current node, or if the new node should become the head node of the list.

The remove member returns a pointer to the object that was in the specified node. You are responsible for deallocating the memory for this object! The destroy member deallocates the memory used by the object in the current node. In both cases the iterator is left pointing to the node previous to the one that was deleted.

All of the list traversal functions (prev, next, current, etc) return a pointer to the contents of the node on which they are operating. You should test the pointer to see if it is NULL before you dereference it. When you call any of the traversal functions, the list's internal iterator is left pointing to the node to which traversal function moved. You can create additional iterators (external to the list) to keep track of multiple positions in the list.

typedefs and constants
GAListBASE::HEAD
GAListBASE::TAIL
GAListBASE::BEFORE
GAListBASE::AFTER
constructors
GAListIter(const GAList<T> &)
member function index
  T * current()
  T * head()
  T * tail()
  T * next()
  T * prev()
  T * warp(const GAList<T>& t)
  T * warp(const GAListIter<T>& i)
  T * warp(unsigned int i)
constructors
GAList()
GAList(const T& t)
GAList(const GAList<T>& orig)
member function index
GAList<T> * clone()
       void copy(const GAList<T>& orig)
       void destroy()
       void swap(unsigned int, unsigned int)
        T * remove()
       void insert(GAList<T> * t, GAListBASE::Location where=AFTER)
       void insert(const T& t, GAListBASE::Location where=AFTER)

        T * current()
        T * head()
        T * tail()
        T * next()
        T * prev()
        T * warp(unsigned int i)
        T * warp(const GAListIter<T>& i)
        T * operator[](unsigned int i)

        int size() const
member function descriptions

These functions change the state of the list.

clone
Return a pointer to an exact duplicate of the original list. The caller is responsible for the memory allocated by the call to this function.
copy
Duplicate the specified list.
destroy
Destroy the current node in the list. This function uses the location of the internal iterator to determine which node should be destroyed. If the head node is destroyed, the next node in the list becomes the head node.
insert
Add a node or list to the list. The insertion is made relative to the location of the internal iterator. The where flag specifies whether the insertion should be made before or after the current node.
remove
Returns a pointer to the contents of the current node and removes the current node from the list. The iterator moves to the previous node. The caller is responsible for the memory used by the contents.
swap
Swap the positions of the two specified nodes. The internal iterator is not affected. If the iterator was pointing to one of the nodes before the swap it will still point to that node after the swap, even if that node was swapped.

These functions do not change the contents of the list, but they change the state of the list's internal iterator (when invoked on a list object).

current
Returns a pointer to the contents of the current node.
head
Returns a pointer to the contents of the first node in the list.
next
Returns a pointer to the contents of the next node.
operator[]
Returns a pointer to the contents of the ith node in the list (same as warp).
prev
Returns a pointer to the contents of the previous node.
tail
Returns a pointer to the contents of the last node in the list.
warp
Returns a pointer to the contents of the ith node in the list, or a pointer to the element in the list pointed to by the specified iterator. The head node is number 0.




GATree<T> and GATreeIter<T>

The GATree<T> object is defined for your convenience so that you do not have to create your own tree object. It is a template-ized container class whose nodes can contain objects of any type. Each level in the GATree<T> object is a circular and doubly-linked list. The eldest child of a level is the head of the linked list, each child in a level points to its parent, and the parent of those children points to the eldest child. Any tree can have only one root node. Any node can have any number of children. A tree iterator is also defined to be used when moving around the list to keep track of the current, next, parent, or whichever node. Iterators do not change the state of the tree.

tree The GATree object
The circles are nodes in the tree. Each node contains a user-specified object; the initialization method determines the tree topology and the contents of each node. Each tree contains one (and only one) root node. Each level in the tree is a circular, doubly linked list. The head of each list is called the 'eldest' child, each node in a level has a link to its parent, and each parent has a link to the eldest of its children (if it has any children).

The template-ized GATree<T> is derived from a generic tree base class called GATreeBASE. The template tree is defined in treetmpl.h, the tree base class is defined in treebase.h

Any object used in the nodes have the following methods defined and publicly available:

  • copy constructor
  • operator =
  • operator ==
  • operator !=

Each tree object contains an iterator. The tree's traversal member functions (next, prev, etc) simply call the member functions on the internal iterator. You can also instantiate iterators external to the tree object so that you can traverse the tree without modifying its contents.

The tree base class defines constants for specifying where insertions should occur.

Nodes in a tree are numbered starting at 0 then increasing in a depth-first traversal of the tree. The root node is node 0. A tree can have only one root node, but any node in the tree can have any number of children.

When you do an insertion, the tree makes a copy of the specified object (allocating space for it in the process). The internal iterator is left pointing to the node which was just inserted. The insertion function uses the copy constructor member to do this, so the objects in your tree must have a copy constructor defined. The new node is inserted relative to the current location of the tree's internal iterator. Use the where flag to determine whether the new node will be inserted before, after, or below the current node, or if the new node should become the root node of the tree.

The remove member returns a pointer to a tree. The root node of this tree is the node at which the iterator was pointing. You are responsible for deallocating the memory for this tree! The destroy member deallocates the memory used by the object in the current node and completely destroys any subtree hanging on that node. In both cases, the iterator is left pointing to the elder child or parent of the node that was removed/destroyed.

All of the tree traversal functions (prev, next, current, etc) return a pointer to the contents of the node on which they are operating. You should test the pointer to see if it is NULL before you dereference it. Also, the iterator is left pointing to the node to which you traverse with each traversal function. You can create additional iterators (external to the tree) to keep track of multiple positions in the tree.

typedefs and constants
GATreeBASE::ROOT
GATreeBASE::BEFORE
GATreeBASE::AFTER
GATreeBASE::BELOW
constructors
GATreeIter(const GATree<T>& t)
member function index
        T * current()
        T * root()
        T * next()
        T * prev()
        T * parent()
        T * child()
        T * eldest()
        T * youngest()
        T * warp(const GATree<T>& t)
        T * warp(const GATreeIter<T>& i)
        T * warp(unsigned int i)

        int size()
        int depth()
        int nchildren()
        int nsiblings()
constructors
GATree()
GATree(const T& t)
GATree(const GATree<T>& orig)
member function index
GATree<T> * clone()
       void copy(const GATree<T>& orig)
       void destroy()
       void swaptree(GATree<T> * t)
       void swaptree(unsigned int, unsigned int)
       void swap(unsigned int, unsigned int)
GATree<T> * remove()
       void insert(GATree<T> * t, GATreeBASE::Location where=BELOW)
       void insert(const T& t, GATreeBASE::Location where=BELOW)

        T * current()
        T * root()
        T * next()
        T * prev()
        T * parent()
        T * child()
        T * eldest()
        T * youngest()
        T * warp(unsigned int i)
        T * warp(const GATreeIter<T>& i)

        int ancestral(unsigned int i, unsigned int j) const
        int size()
        int depth()
        int nchildren()
        int nsiblings()
member function descriptions

These functions change the state of the tree.

clone
Return a pointer to an exact duplicate of the original tree. The caller is responsible for the memory allocated by the call to this function.
copy
Duplicate the specified tree.
destroy
Destroy the current node in the tree. If the node has children, the entire sub-tree connected to the node is destroyed as well. This function uses the location of the internal iterator to determine which node should be destroyed. If the root node is destroyed, the entire contents of the tree will be destroyed, but the tree object itself will not be deleted.
insert
Add a node or tree to the tree. The insertion is made relative to the location of the internal iterator. The where flag specifies whether the insertion should be made before, after, or below the current node.
remove
Returns a pointer to a new tree object whose root node is the (formerly) current node of the original tree. Any subtree connected to the node stays with the node. The iterator moves to the previous node in the current generation, or the parent node if no elder sibling exists. The caller is responsible for the memory used by the new tree.
swap
Swap the contents of the two specified nodes. Sub-trees connected to either node are not affected; only the specified nodes are swapped.
swaptree
Swap the contents of the two specified nodes as well as any sub-trees connected to the specified nodes.
These functions do not change the contents of the tree, but they change the state of the tree's internal iterator (when invoked on a tree object).
ancestral
Returns 1 if one of the two specified nodes is the ancestor of the other, returns 0 otherwise.
child
Returns a pointer to the contents of the eldest child of the current node. If the current node has no children, this function returns NULL.
current
Returns a pointer to the contents of the current node.
depth
Returns the number of generations (the depth) of the tree. When called as the member function of a tree iterator, this function returns the depth of the subtree connected to the iterator's current node.
eldest
Returns a pointer to the contents of the eldest node in the current generation. The eldest node is the node pointed to by the 'child' function in the node's parent.
nchildren
Returns the number of children of the node to which the iterator is pointing.
next
Returns a pointer to the contents of the next node in the current generation.
nsiblings
Returns the number of nodes in the level of the tree as the node to which the iterator is pointing.
parent
Returns a pointer to the contents of the parent of the current node. If the current node is the root node, this function returns NULL.
prev
Returns a pointer to the contents of the previous node in the current generation.
root
Returns a pointer to the contents of the root node of the tree.
size
Returns the number of nodes in the tree. When called as the member function of a tree iterator, this function returns the size of the subtree connected to the iterator's current node.
warp
Returns a pointer to the contents of the ith node in the tree, or a pointer to the element in the tree pointed to by the specified iterator. The head node is number 0 then the count increases as a depth-first traversal of the tree.
youngest
Returns a pointer to the contents of the youngest node in the current generation.

Matthew Wall, 28 May 1996 galib247/doc/ClassHierarchy.html0100644003643600364360000001115110573535471015776 0ustar mwallmwallGAlib: Class Hierarchy GAlib Classes
version 2.4.x

Here is an outline of the GAlib class hierarchy. The first section is a graphic map, the second section contains an outline of the hierarchy with hot links to the class descriptions. Please see the programming interface for details about the member functions. Or see the overview for an explanation of the design philosophy behind GAlib.


algorithm      scaling      scaling


genome

Matthew Wall, 14 February 1996 galib247/doc/Copyright.html0100644003643600364360000000401210573535471015040 0ustar mwallmwallGAlib: Copyright
Copyright:

  Copyright (c) 1995-1996 Massachusetts Institute of Technology (MIT)
  Copyright (c) 1996-2005 Matthew Wall (the Author)
     All rights reserved.

Distribution Conditions:

  Redistribution and use in source and binary forms, with or without 
  modification, are permitted provided that the following conditions 
  are met:

     Redistributions of source code must retain the above copyright 
     notice, this list of conditions and the following disclaimer.

     Redistributions in binary form must reproduce the above copyright 
     notice, this list of conditions and the following disclaimer in 
     the documentation and/or other materials provided with the 
     distribution.

     Neither the name Massachusetts Institute of Technology (MIT),
     Matthew Wall, nor the names of contributors may be used to 
     endorse or promote products derived from this software without 
     specific prior written permission. 

Disclaimer:

  This software is provided "as is".  Any express or implied warranties,
  including, but not limited to, the implied warranties of merchantability
  and fitness for a particular purpose are disclaimed.  In no event shall
  MIT, Matthew Wall, or the contributors to GAlib be liable for any direct,
  indirect, incidental, special, exemplary, or consequential damages
  (including, but not limited to, procurement of substitute goods or 
  services; loss of use, data, or profits; or business interruption)
  however caused and on any theory of liability, whether in contract,
  strict liability, or tort (including negligence or otherwise) arising
  in any way out of the use of this software, even if advised of the
  possibility of such damage.



galib247/doc/Extensions.html0100644003643600364360000006347110573535471015245 0ustar mwallmwallGAlib: Extensions Customizing GAlib
version 2.4

This document describes how to extend GAlib's capabilities by defining your own genomes and genetic operators. The best way to customize the behavior of an object is to derive a new class. If you do not want to do that much work, GAlib is designed to let you replace behaviors of existing objects by defining new functions.

see also: library overview, class hierarchy, programming interface

Table of contents







Deriving your own genome class

You can create your own genome class by multiply-inheriting from the base genome class and your own data type. For example, if you have already have an object defined, say MyObject, then you would derive a new genome class called MyGenome, whose class definition looks like this:
// Class definition for the new genome object, including statically defined
// declarations for default evaluation, initialization, mutation, and 
// comparison methods for this genome class.
class MyGenome : public MyObject, public GAGenome {
public:
  GADefineIdentity("MyGenome", 201);
  static void Init(GAGenome&);
  static int Mutate(GAGenome&, float);
  static float Compare(const GAGenome&, const GAGenome&);
  static float Evaluate(GAGenome&);
  static int Cross(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*);

public:
  MyGenome() : GAGenome(Init, Mutate, Compare) { 
    evaluator(Evaluate); 
    crossover(Cross); 
  }
  MyGenome(const MyGenome& orig) { copy(orig); }
  virtual ~MyGenome() {}
  MyGenome& operator=(const GAGenome& orig){
    if(&orig != this) copy(orig);
    return *this;
  }

  virtual GAGenome* clone(CloneMethod) const {return new MyGenome(*this);}
  virtual void copy(const GAGenome& orig) {
    GAGenome::copy(orig);  // this copies all of the base genome parts
    // copy any parts of MyObject here
    // copy any parts of MyGenome here
  }

  // any data/member functions specific to this new class
};

void 
MyGenome::Init(GAGenome&){
  // your initializer here
}

int 
MyGenome::Mutate(GAGenome&, float){
  // your mutator here
}

float 
MyGenome::Compare(const GAGenome&, const GAGenome&){
  // your comparison here
}

float 
MyGenome::Evaluate(GAGenome&){
  // your evaluation here
}

int
MyGenome::Cross(const GAGenome& mom, const GAGenome& dad,
                GAGenome* sis, GAGenome* bro){
  // your crossover here
}

By convention, one of the arguments to a derived genome constructor is the objective function. Alternatively (as illustrated in this example), you can hard code a default objective function into your genome - just call the evaluator member somewhere in your constructor and pass the function you want used as the default.

Once you have defined your genome class, you should define the intialization, mutation, comparison, and crossover operators for it. The comparison operator is optional, but if you do not define it you will not be able to use the diversity measures in the genetic algorithms and/or populations.

Note that the genetic comparator is not necessarily the same as the boolean operator== and operator!= comparators. The genetic comparator returns 0 if the two individuals are the same, -1 if the comparison fails for some reason, and a real number greater than 0 indicating the degree of difference if the individuals are not identical but can be compared. It may be based on genotype or phenotype. The boolean comparators, on the other hand, indicate only whether or not two individuals are identical. In most cases, the boolean comparator can simply call the genetic comparator, but in some cases it is more efficient to define different operators (the boolean comparators are called much more often than the genetic comparators, especially if no diversity is being measured).

To work properly with the GAlib, you must define the following:

       MyGenome( -default-args-for-your-genome-constructor )
       MyGenome(const MyGenome&)
       virtual GAGenome* clone(GAGenome::CloneMethod) const
If your genome adds any non-trivial member data, you must define these:
       virtual ~MyGenome()
       virtual copy(const GAGenome&)
       virtual int equal(const GAGenome&) const
To enable streams-based reading and writing of your genome, you should define these:
       virtual int read(istream&)
       virtual int write(ostream&) const
When you derive a genome, don't forget to use the _evaluated flag to indicate when the state of the genome has changed and an evaluation is needed. If a member function changes the state of your genome, that member function should set the _evaluated flag to gaFalse.

Assign a default crossover, mutation, initialization, and comparison method so that users don't have to assign one unless they want to.

It is a good idea to define an identity for your genome (especially if you will be using it in an environment with multiple genome types running around). Use the DefineIdentity macro (defined in id.h) to do this in your class definition. The DefineIdentity macro sets a class ID number and the name that will be used in error messages for the class. You can use any number above 200 for the ID, but be sure to use a different number for each of your classes.

When run-time type information (RTTI) has stabilized across compilers, GAlib will probably use that instead of the Define/Declare identity macros.





Genome Testing

Use the following program to test your genome. The basic idea here is to test incrementally in order to isolate problems as they arise. If your genome works with a small test program such as this one, it will function properly with any genetic algorithm in GAlib. (This is no guarantee, however, that your genome will help you find the solution to your problem. That is another matter entirely.)
int
main() {
  MyGenome genome;      // test default constructor (if we have one)
  cout << "genome after creation:\n" << genome << endl;

  genome.initialize();  // test the initializer
  cout << "genome after initialization:\n" << genome << endl;

  genome.mutate();      // test the mutator
  cout << "genome after mutation:\n" << genome << endl;

  MyGenome* a = new MyGenome(genome);   // test copy constructor
  MyGenome* b = new MyGenome(genome);

  MyGenome* c = genome.clone(GAGenome::CONTENTS);
  cout << "clone contents:\n" << *c << "\n";
  MyGenome* d = genome.clone(GAGenome::ATTRIBUTES);
  cout << "clone attributes:\n" << *d << "\n";

  a->initialize();
  b->initialize();
  cout << "parents:\n" << *a << "\n" << *b << "\n";

  MyGenome::DefaultCrossover(*a, *b, c, d);   // test two child crossover
  cout << "children of crossover:\n" << *c << "\n" << *d << "\n";
  MyGenome::DefaultCrossover(*a, *b, c, 0);   // test single child crossover
  cout << "child of crossover:\n" << *c << "\n";

  a->compare(*b);       // test the comparator

  delete a;
  delete b;
  delete c;
  delete d;

  return 0;
}




Genome Initialization

The initializer takes a single argument: the genome to be initialized. The genome has already been allocated; the intializer only needs to populate it with appropriate contents.

Here is the implementation of an initializer for the GATreeGenome<int> class.

void
TreeInitializer(GAGenome & c)
{
  GATreeGenome<int> &child=(GATreeGenome<int> &)c;

// destroy any pre-existing tree
  child.root();
  child.destroy();

// Create a new tree with depth of 'depth' and each eldest node containing
// 'n' children (the other siblings have none).
  int depth=2, n=3, count=0;
  child.insert(count++,GATreeBASE::ROOT);

  for(int i=0; i<depth; i++){
    child.eldest();
    child.insert(count++);
    for(int j=0; j<n; j++)
      child.insert(count++,GATreeBASE::AFTER);
  }
}




Genome Mutation

The genome mutator takes two arguments: the genome that will receive the mutation(s) and a mutation probability. The exact meaning of the mutation probability is up to the designer of the mutation operator. The mutator should return the number of mutations that occured.

Most genetic algorithms invoke the mutation method on each newly generated offspring. So your mutation operator should base its actions on the value of the mutation probability. For example, an array of floats could flip a pmut-biased coin for each element in the array. If the coin toss returns true, the element gets a Gaussian mutation. If it returns false, the element is left unchanged. Alternatively, a single biased coin toss could be used to determine whether or not the entire genome should be mutated.

Here is an implementation of the flip mutator for the GA1DBinaryString class. This mutator flips a biased coin for each bit in the string.

int 
GA1DBinStrFlipMutator(GAGenome & c, float pmut)
{
  GA1DBinaryStringGenome &child=(GA1DBinaryStringGenome &)c;
  if(pmut <= 0.0) return(0);

  int nMut=0;
  for(int i=child.length()-1; i>=0; i--){
    if(GAFlipCoin(pmut)){
      child.gene(i, ((child.gene(i) == 0) ? 1 : 0));
      nMut++;
    }
  }
  return nMut;
}




Genome Crossover

The crossover method is used by the genetic algorithm to mate individuals from the population to form new offspring. Each genome should define a default crossover method for the genetic algorithms to use. The sexual and asexual member functions return a pointer to the preferred sexual and asexual mating methods, respectively. The crossover member function is used to change the preferred mating method. The genome does not have a member function to invoke the crossover; only the genetic algorithm can actually perform the crossover.

Some genetic algorithms use sexual mating, others use asexual mating. If possible, define both so that your genome will work with either kind of genetic algorithm. If your derived class does not define a cross method, an error message will be posted whenever crossover is attempted.

Sexual crossover takes four arguments: two parents and two children. If one child is nil, the operator should be able to generate a single child. The genomes have already been allocated, so the crossover operator should simply modify the contents of the child genome as appropriate. The crossover function should return the number of crossovers that occurred. Your crossover function should be able to operate on one or two children, so be sure to test the child pointers to see if the genetic algorithm is asking you to create one or two children.

Here is an implementation of the two-parent/one-or-two-child single point crossover operator for fixed-length genomes of the GA1DBinaryStringGenome class.

int
SinglePointCrossover(const GAGenome& p1, const GAGenome& p2, GAGenome* c1, GAGenome* c2){
  GA1DBinaryStringGenome &mom=(GA1DBinaryStringGenome &)p1;
  GA1DBinaryStringGenome &dad=(GA1DBinaryStringGenome &)p2;

  int n=0;
  unsigned int site = GARandomInt(0, mom.length());
  unsigned int len = mom.length() - site;

  if(c1){
    GA1DBinaryStringGenome &sis=(GA1DBinaryStringGenome &)*c1;
    sis.copy(mom, 0, 0, site);
    sis.copy(dad, site, site, len);
    n++;
  }
  if(c2){
    GA1DBinaryStringGenome &bro=(GA1DBinaryStringGenome &)*c2;
    bro.copy(dad, 0, 0, site);
    bro.copy(mom, site, site, len);
    n++;
  }

  return n;
}




Genome Comparison

The comparison method is used for diversity calculations. It compares two genomes and returns a number that is greater than or equal to zero. A value of 0 means that the two genomes are identical (no diversity). There is no maximum value for the return value from the comparator. A value of -1 indicates that the diversity could not be calculated.

Here is the comparator for the binary string genomes. It simply counts up the number of bits that both genomes share. In this example, we return a -1 if the genomes are not the same length.

float
GA1DBinStrComparator(const GAGenome& a, const GAGenome& b){
  GA1DBinaryStringGenome &sis=(GA1DBinaryStringGenome &)a;
  GA1DBinaryStringGenome &bro=(GA1DBinaryStringGenome &)b;
  if(sis.length() != bro.length()) return -1;
  float count = 0.0;
  for(int i=sis.length()-1; i>=0; i--)
    count += ((sis.gene(i) == bro.gene(i)) ? 0 : 1);
  return count/sis.length();
}




Genome Evaluation

The genome evaluator is the objective function for your problem. It takes a single genome as its argument. The evaluator returns a number that indicates how good or bad the genome is. You must cast the generic genome to the genome type that you are using. If your objective function works with different genome types, then use the genome object's className and/or classID member functions to determine the genome class before you do the casts.

Here is a simple evaluation function for a real number genome with a single element. The function tries to maximize a sinusoidal.

float
Objective(GAGenome& g){
  GARealGenome& genome = (GARealGenome &)g;
  return 1 + sin(genome.gene(0)*2*M_PI);
}




Population Initialization

This method is invoked when the population is initialized.

Here is an implemenation that invokes the initializer for each genome in the population.

void 
PopInitializer(GAPopulation & p){
  for(int i=0; i<p.size(); i++)
    p.individual(i).initialize();
}




Population Evaluation

This method is invoked when the population is evaluated. If your objective is population-based, you can use this method to set the score for each genome rather than invoking an evaluator for each genome.

Here is an implementation that invokes the evaluation method for each genome in the population.

void 
PopEvaluator(GAPopulation & p){
  for(int i=0; i<p.size(); i++)
    p.individual(i).evaluate();
}




Scaling Scheme

The scaling object does the transformation from raw (objective) scores to scaled (fitness) scores. The most important member function you will have to define for a new scaling object is the evaluate member function. This function calculates the fitness scores based on the objective scores in the population that is passed to it.

The GAScalingScheme class is a pure virtual (abstract) class and cannot be instantiated. To make your derived class non-virtual, you must define the clone and evaluate functions. You should also define the copy method if your derived class introduces any additional data members that require non-trivial copy.

The scaling class is polymorphic, so you should define the object's identity using the GADefineIdentity macro. This macro sets a class ID number and the name that will be used in error messages for the class. You can use any number above 200 for the ID, but be sure to use a different number for each of your objects.

Here is an implementation of sigma truncation scaling.

class SigmaTruncationScaling : public GAScalingScheme {
public:
  GADefineIdentity("SigmaTruncationScaling", 286);

  SigmaTruncationScaling(float m=gaDefSigmaTruncationMultiplier) : c(m) {}
  SigmaTruncationScaling(const SigmaTruncationScaling & arg){copy(arg);}
  SigmaTruncationScaling & operator=(const GAScalingScheme & arg)
    { copy(arg); return *this; }
  virtual ~SigmaTruncationScaling() {}
  virtual GAScalingScheme * clone() const 
    { return new SigmaTruncationScaling(*this); }
  virtual void evaluate(const GAPopulation & p);
  virtual void copy(const GAScalingScheme & arg){
    if(&arg != this && sameClass(arg)){
      GAScalingScheme::copy(arg);
      c=((SigmaTruncationScaling&)arg).c;
    }
  }
  float multiplier(float fm) { return c=fm; }
  float multiplier() const { return c; }
protected:
  float c;			// std deviation multiplier
};


void 
SigmaTruncationScaling::evaluate(const GAPopulation & p) {
  float f;
  for(int i=0; i<p.size(); i++){
    f = p.individual(i).score() - p.ave() + c * p.dev();
    if(f < 0) f = 0;
    p.individual(i).fitness(f);
  }
}




Selection Scheme

The selection object is used to pick individuals from the population. Before a selection occurs, the update method is called. You can use this method to do any pre-selection data transformations for your selection scheme. When a selection is requested, the select method is called. The select method should return a reference to a single individual from the population.

A selector may make its selections based either on the scaled (fitness) scores or on the raw (objective) scores of the individuals in the population. Note also that a population may be sorted either low-to-high or high-to-low, depending on which sort order was chosen. Your selector should be able to handle either order (this way it will work with genetic algorithms that maximize or minimize).

The selection scheme class is polymorphic, so you should define the object's identity using the GADefineIdentity macro. This macro sets a class ID number and the name that will be used in error messages for the class. You can use any number above 200 for the ID, but be sure to use a different number for each of your objects.

Here is an implementation of a tournament selector. It is based on the roulette wheel selector and shares some of the roulette wheel selector's functionality. In particular, this tournament selector uses the roulette wheel selector's update method, so it does not define its own. The select method does two fitness-proportionate selections then returns the individual with better score.

class TournamentSelector : public GARouletteWheelSelector {
public:
  GADefineIdentity("TournamentSelector", 255);

  TournamentSelector(int w=GASelectionScheme::FITNESS) : 
  GARouletteWheelSelector(w) {}
  TournamentSelector(const TournamentSelector& orig) { copy(orig); }
  TournamentSelector& operator=(const GASelectionScheme& orig) 
    { if(&orig != this) copy(orig); return *this; }
  virtual ~TournamentSelector() {}
  virtual GASelectionScheme* clone() const
    { return new TournamentSelector; }
  virtual GAGenome& select() const;
};


GAGenome &
TournamentSelector::select() const {
  int picked=0;
  float cutoff;
  int i, upper, lower;

  cutoff = GARandomFloat();
  lower = 0; upper = pop->size()-1;
  while(upper >= lower){
    i = lower + (upper-lower)/2;
    if(psum[i] > cutoff)
      upper = i-1;
    else
      lower = i+1;
  }
  lower = Min(pop->size()-1, lower);
  lower = Max(0, lower);
  picked = lower;

  cutoff = GARandomFloat();
  lower = 0; upper = pop->size()-1;
  while(upper >= lower){
    i = lower + (upper-lower)/2;
    if(psum[i] > cutoff)
      upper = i-1;
    else
      lower = i+1;
  }
  lower = Min(pop->size()-1, lower);
  lower = Max(0, lower);

  GAPopulation::SortBasis basis = 
    (which == FITNESS ? GAPopulation::SCALED : GAPopulation::RAW);
  if(pop->order() == GAPopulation::LOW_IS_BEST){
    if(pop->individual(lower,basis).score() <
       pop->individual(picked,basis).score())
      picked = lower;
  }
  else{
    if(pop->individual(lower,basis).score() >
       pop->individual(picked,basis).score())
      picked = lower;
  }

  return pop->individual(picked,basis);
}




Genetic Algorithm

Here is a sample derived class that does restricted mating. In this example, one of the parents is selected as usual. The second individual is select as the first, but it is used only if it is similar to the first individual. If not, we make another selection. If enough selections fail, we take what we can get.
class RestrictedMatingGA : public GASteadyStateGA {
public:
  GADefineIdentity("RestrictedMatingGA", 288);
  RestrictedMatingGA(const GAGenome& g) : GASteadyStateGA(g) {}
  virtual ~RestrictedMatingGA() {}
  virtual void step();
  RestrictedMatingGA & operator++() { step(); return *this; }
};

void
RestrictedMatingGA::step()
{ 
  int i, k;
  for(i=0; i<tmpPop->size()-; i++){
    mom = &(pop->select()); 
    k=0;
    do { k++; dad = &(pop->select()); }
    while(mom->compare(*dad) < THRESHOLD && k<pop->size());
    stats.numsel += 2;
    if(GAFlipCoin(pCrossover()))
      stats.numcro += (*scross)(*mom, *dad, &tmpPop->individual(i), 0);
    else
      tmpPop->individual(i).copy(*mom);
    stats.nummut += tmpPop->individual(i).mutate(pMutation());
  }

  for(i=0; i<tmpPop->size(); i++)
    pop->add(tmpPop->individual(i));

  pop->evaluate();		// get info about current pop for next time
  pop->scale();			// remind the population to do its scaling

  for(i=0; i<tmpPop->size(); i++)
    pop->destroy(GAPopulation::WORST, GAPopulation::SCALED);

  stats.update(*pop);		// update the statistics by one generation
}




Termination Function

The termination function determines when the genetic algorithm should stop evolving. It takes a genetic algorithm as its argument and returns gaTrue if the genetic algorithm should stop or gaFalse if the algorithm should continue.

Here are three examples of termination functions. The first compares the current generation to the desired number of generations. If the current generation is less than the desired number of generations, it returns gaFalse to signify that the GA is not yet complete.

GABoolean
GATerminateUponGeneration(GAGeneticAlgorithm & ga){
  return(ga.generation() < ga.nGenerations() ? gaFalse : gaTrue);
}
The second example compares the average score in the current population with the score of the best individual in the current population. If the ratio of these exceeds a specified threshhold, it returns gaTrue to signify that the GA should stop. Basically this means that the entire population has converged to a 'good' score.
const float desiredRatio = 0.95;    // stop when pop average is 95% of best

GABoolean
GATerminateUponScoreConvergence(GAGeneticAlgorithm & ga){
  if(ga.statistics().current(GAStatistics::Mean) /
     ga.statistics().current(GAStatistics::Maximum) > desiredRatio)
    return gaTrue;
  else
    return gaFalse;
}
The third uses the population diversity as the criterion for stopping. If the diversity drops below a specified threshhold, the genetic algorithm will stop.
const float thresh = 0.01;     // stop when population diversity is below this

GABoolean
StopWhenNoDiversity(GAGeneticAlgorithm & ga){
  if(ga.statistics().current(GAStatistics::Diversity) < thresh)
    return gaTrue;
  else
    return gaFalse;
}
A faster method of doing a nearly equivalent termination is to use the population's standard deviation as the stopping criterion (this method does not require comparisons of each individual). Notice that this judges diversity based upon the genome scores rather than their actual genetic diversity.
const float thresh = 0.01;     // stop when population deviation is below this

GABoolean
StopWhenNoDeviation(GAGeneticAlgorithm & ga){
  if(ga.statistics().current(GAStatistics::Deviation) < thresh)
    return gaTrue;
  else
    return gaFalse;
}

Matthew Wall, 23 March 1996 galib247/doc/FeatureList.html0100644003643600364360000001126310573535471015325 0ustar mwallmwallGAlib: List of Features Feature List for GAlib
version 2.4
General features
  • Many examples are included illustrating the use of various GAlib features, class derivations, parallelization, deterministic crowding, travelling salesman, DeJong, and Royal Road problems.
  • The library has been used on various DOS/Windows, Windows NT/95, MacOS, and UNIX configurations. GAlib compiles without warnings on most major compilers.
  • Templates are used in some genome classes, but GAlib can be used without templates if your compiler does not understand them.
  • Four random number generators are included with the library. You can select the one most appropriate for your system, or use your own.
Algorithms, Parameters, and Statistics
  • GAlib can be used with PVM (parallel virtual machine) to evolve populations and/or individuals in parallel on multiple CPUs.
  • Genetic algorithm parameters can be configured from file, command-line, and/or code.
  • Overlapping (steady-state GA) and non-overlapping (simple GA) populations are supported. You can also specify the amount of overlap (% replacement). The distribution includes examples of other derived genetic algorithms such as a genetic algorithm with sub-populations and another that uses deterministic crowding.
  • New genetic algorithms can be quickly tested by deriving from the base genetic algorithm classes in the library. In many cases you need only overide one virtual function.
  • Built-in termination methods include convergence and number-of-generations. The termination method can be customized for any existing genetic algorithm class or for new classes you derive.
  • Speciation can be done with either DeJong-style crowding (using a replacement strategy) or Goldberg-style sharing (using fitness scaling).
  • Elitism is optional for non-overlapping genetic algorithms.
  • Built-in replacement strategies (for overlapping populations) include replace parent, replace random, replace worst. The replacement operator can be customized.
  • Built-in selection methods include rank, roulette wheel, tournament, stochastic remainder sampling, stochastic uniform sampling, and deterministic sampling. The selection operator can be customized.
  • "on-line" and "off-line" statistics are recorded as well as max, min, mean, standard deviation, and diversity. You can specify which statistics should be recorded and how often they should be flushed to file.
Genomes and Operators
  • Chromosomes can be built from any C++ data type. You can use the types built-in to the library (bit-string, array, list, tree) or derive a chromosome based on your own objects.
  • Built-in chromosome types include real number arrays, list, tree, 1D, 2D, and 3D arrays, 1D, 2D, and 3D binary string. The binary strings, strings, and arrays can be variable length. The lists and trees can contain any object in their nodes. The array can contain any object in each element.
  • All chromosome initialization, mutation, crossover, and comparison methods can be customized.
  • Built-in initialization operators include uniform random, order-based random, allele-based random, and initialize-to-zero.
  • Built-in mutation operators include random flip, random swap, Gaussian, destructive, swap subtree, swap node.
  • Built-in crossover operators include arithmetic, blend, partial match, ordered, cycle, single point, two point, even, odd, uniform, node- and subtree-single point. Edge recombination is included in the examples.
  • Dominance and Diploidy are not explicitly built in to the library, but any of the genome classes in the library can easily be extended to become diploid chromosomes.
Objective function
  • Objective functions can be population- or individual-based.
  • If the built-in genomes adequately represent your problem, a user-specified objective function is the only problem-specific code that must be written.

Matthew Wall, 19 August 1996 galib247/doc/GAlib.html0100755003643600364360000000542610573535471014063 0ustar mwallmwallGAlib: Matthew's C++ Genetic Algorithms Library GAlib Documentation
version 2.4

GAlib is a set of C++ genetic algorithm objects. The library includes tools for using genetic algorithms to do optimization in any C++ program. This documentation includes:

installation instructions
overview of the GAlib implementation and programming techniques
class hierarchy of GAlib objects
programming interface for using GAlib classes
instructions for deriving new classes and genetic operators
descriptions of the examples
list of features
other genetic algorithm sites

For the most recent GAlib developments, please refer to http://lancet.mit.edu/ga/

change history
bug list
frequently asked questions
mailing list archive

There are two mailing lists to which you may subscribe:

galib@mit.edu
This is an unmoderated mailing list for GAlib users. If you have found use for GAlib and would like to let other users know about it, or if you're having problems with GAlib, post it to this mailing list and one of the other subscribers just might be able to help you out. I read all messages that are posted to this list, but I cannot respond to every one.

galib-announce@mit.edu
This mailing list is for announcements about updates to GAlib. The only messages sent to recipients of this list are announcements from me about revisions to GAlib. This typically amounts to about one or two emails per year.
To subscribe, send email to galib-request@mit.edu with the word subscribe as the subject. To unsubscribe, send email with the word unsubscribe as the subject.

Copyright (c) Massachusetts Institute of Technology and Matthew Wall. All rights reserved.

galib247/doc/images/0040755003643600364360000000000010573535777013466 5ustar mwallmwallgalib247/doc/images/ArraySinglePointCrossover.gif0100644003643600364360000000045110573535470021300 0ustar mwallmwallGIF89ag>€ÿÿÿ!ù,g>þŒ©Ëí£œ´Ú‹³Þ¼{|âh…ä‰2fʦk ‹/ ÔöçúÎ÷þ´5j±ˆ<*“Ì¥³ uŸÔ(Re­j³Ü­·›œ!¦à¯¹>±jtûínŠÁºýŽÆ`ó½¿ô˜Ñ'X8´——¨¸øshøAHøèRI)1 ¹ ‰™ÐI!É8JªèÙzú—ªŠH)Ôzex‹I[+xS‹ë7ÃÚI\xKHt¬¼ÌÜìü -=M­Zz 4ǧ !é=Þ½$¬RNNþ žþŽvΙM_Ï[Ÿ¯¿lïŸ}IxXšÁ3"ÎàAY Ø=Z˜lÞ¿‰ŒøY¼ˆ1#Š;galib247/doc/images/ArraySinglePointCrossover1.gif0100644003643600364360000000046410573535470021365 0ustar mwallmwallGIF89a„?€ÿÿÿ!ù,„?þŒ©Ëí£œ´Ú‹³Þ¼û†âH–扦êÊN@ ÇÉ+×€çúÎ÷þüÙ4¯bÀˆ<*“ÌåçlJià TÍb·Ú.µZኽË+y ¶Ž×ç66Êçô9üŽøâ÷3‰žøÇ ˆGXS§¸ÈØè˜Ãqè‡YID¹!9y‰™¡ñùÚ9ùxŠšºX5JÊ×êj;K §SÛI‹›õäË{'¸œ¢G\l|€œl Ü -=M]m}­½í¢êý ®ØÀFÅLzhV^~îöŽÖ>¾ï$?ž¯¿ÏÝïÿ0 ‚}Œ°»QÉAL Õ%TrÏÓC$ )5¤—¤A q;zü2¤Èd;galib247/doc/images/ArrayUniformCrossover.gif0100644003643600364360000000064510573535470020471 0ustar mwallmwallGIF89an7€ÿÿÿ!ù,n7þŒ©Ëí£œ´Ú‹³Þ¼3†âH–扦êº*`Àr8Ï/çð]ã=¯ mAboWL‹¹Û°ÉD}K)óiýE_Ê-÷ {·Æëx:T–µÙª}¦®Ýì«‹…Ïë÷|‘ç(8HXhx8ا¸È¸ç‚si0É%# ™‰¹I©yÙÉù):9êJŠ*YišzÊê *[:Û*kyKkûÊ» Lê;œÛ;ü««l¬Úèü (=M]m}­½ÍÝmAã¾ #^Ž)l¾íç—Î-ŒÞ޽ïMN_¯¿Ïßïÿ0 À Ð ìó¨I&(5TMyÅÐ2J^¶±q§!E}4Á°ª˜ìÜE‡o$vR(RÉ#®"NÄòäE”’l´“ÒÉGŽ!eª¼YGŃD‹žˆ4©Ò¥L7} ÕÒ)›¥h~¢³Ì¥eT—©É¹Sb¥˜£â°äeÕkXdisví(fÇZµB«Êªñ*YTfß‚íY3ª`ƒM ><¨;galib247/doc/images/GAArray.gif0100644003643600364360000000147110573535470015431 0ustar mwallmwallGIF89aÝ[€ÿÿÿ!ù,Ý[þŒ©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇòL×öúÎ÷þ ‡Ä¢ñˆL*—KÀ }<¥QÇÔZm\µYÆÖÛ]|ÅaÅØ\Î¥g5õ…så`:ÙŽÆ»ãüy¿þw˜7¸çwˆ(¨HÈh˜¹Ù8ù(yIi°ÕƶvÀùé©):ª×‰ªz:¸IjZ ;Ë*[‹K[˜º»ÚÛêÈì; \)|LœlŒi™ùìÜ< ]-­Lm½ÍÌýímû;^\¾|®~ÍÞݾî?Ÿ^/ž{«kžOÞÏ¿Ý?ÕÝ{wP^Bz 6´÷,&+Z¼ˆ1£Fþ&¤"ÄòØácÇ‘µ@rY’$9“P®TiŽ¥—1a¢“™æM›qbÐÙ“§=Ÿ€*ލ£I‘"TZéS§ ¡RZ•*=«°nÕºP‚×°\ņ<{mKµ3ÙætûnQ¹KéFµ{oW½fÓú]û·mà·ƒãž{¸n⻋ó6Þû$²,É”'[®Œù²æÌœ7{î ú³èФG›.šoÙÕ`ǺVÝvÊÙ/i×´½wPÝGy7õ=xVá_‰“ý¸/àå‚™vn:b銩3¶îûÞ䬿æŽ\»òæäŸ—~~zúê믷Ïþ~»øîµëß¶Ÿÿný½þùÿö€Ã XÇy§Zj žÆà‚6áƒFaxñg¢—!‡n"†²×¡z!žha‰$¢Èâ~÷½˜Œ-ÞðÝ|`ÍøBÒ'#Ž4訢{>âäˆB9dˆEšˆd’.¹"“R:©¤lŽEe nI!— fÙ"”G‚Iæ•VöXæb—f›ý¡ œn²¸¦|sÞy ™àá©æ™1ò¦Ÿ.þ (ŠuŠX(˜‡òHh¢ .z££3@Š ¤tv‰©—¢Yj¨ œ~:f” ‚J騦Ú䩎–ªj«þçjš¬ÆJkžrÖJ¤§¸ž:ë®Iöê«©À;ciP„Fl²Ê.Ël³Î> m´ÒNK­´;galib247/doc/images/GAHierarchy.gif0100644003643600364360000000241510573535470016270 0ustar mwallmwallGIF89aZS³ÿÀÀÀÆÆÆœœœZZZBBB!ù,ZS@ÿc€FÜA¯ÿžTßP\'Ž@ j,ÏtmåÞ¼,À½ p dƒcl ‰‘ˆPÛ©T1e„ªÄ“´v³ø 4½µéR[:Gì÷Emã*,HªHcl});9;z@/Tr•–^’._ŽŽ9G‘¢‘¥©¡†0¯?'M›6¸—¾¿ Žb¥{ƒ¦_©¢Lz'À<›w.º¦Ž©ŸݳŸ†&§}àåå}ßÌS¬7FÔô•óõøD÷uHnOù„ÐÑe‰?OÚíúCËÕ§,]6eÉ2¢Ñ„ ªXÂN@|ÿ¹Ø™VaO¤OÆàµ«V<°ýpXR't&„üÈsc&#ލrd€˜cŽ„*¥§R 0æ)‘JB“CNwxüG!Å>Ò„0|2­'ˆ]b0ŒŠ‰&a‹H}0ê8ñGh$>ÂrÀCA@†KRØ{CZ6„†!ô­Ã¹„º¶¹[Lò­ÚQ0C½Ñˬgû>‹-Ú3i‘Xš+fkAfdhd ÚõÖØ´‡œÞp[51Ä•H‹ËèP C±Q³+n ¶SoÜ„æ,eÄa$r²hî>;Dô¸s9¯"zyì59J‘ÊÅ^ë²H}1Á"Cÿ¼ "Üÿ'*©bŠ5õyßî1H'd,Ð¥åFƒslõ0»©¥ÈSýäË+ÿØ €<ìvRL{‘˜_Æà1Ìfc áQõ_-Ï€Yyi¸áDÚ°‹9Ï<ÒŸc† &W Hƒ²ƒ“JäpB-8 Ó/ª!¥h,õ8Í(ÞfA0¡Tƒ6kaMž hAl™1ó×v|±TÒp Ÿ‹F¥’WJºˆRCšr…µ¢¡+ýIg-ÔžaذN:àý—Q(— yÁp‹Dx'j8âXÆ"0¸°jªª6µ©©rÒ*¬±)†õì¤ë%þj¨ÂêCl±‹l#äЕÿa‡HãlWÑ>k­°Á¦GjéìÉð\‘¾ Ç­ç©Þ·ç‚Û¶½õ³lò†«1Ó|µMtÒ°âø‘ù Jgï?D–P.®hI¾ÜM ˆFÿÍÀn½ÿäòÖ`McÆvµÐIÕž”z2ÁÙ¶Ëíb¼øñä½;galib247/doc/images/GATree.gif0100644003643600364360000000230410573535470015246 0ustar mwallmwallGIF89aÕ±€ÿÿÿ!ù,Õ±þŒ©»À£œ´Ú‹³ÞÌñ†âH–Šg¦êʶêÆòLcpçz|ïþÔô‚ÄbÑ4*—Ä$ó ¥9£ÔªijÍj…áö ntÃ䲨Œ.{Óìèº Ëç#€ýNÏÿì¾þ/Õ8ØòöFˆ˜á×q˜è8ÑØø8)!I‰y™É)±Ù Ú`xúhXŠšàEšj ³Ø{‡[k{k‹kÚ'ºKùÊÈú›†¢«IK‰ªg÷îÕN‹»ò°¥º_hUURQ¬ƒoå5 qã\k%›uŒ¶KÜÍ7æ¶MÇ9îS·éj‰¥üØ2êÔ:w¢Zˆ«QÙo=»¢ËCjnÜÂ\O"Õ·ÑŽûMŠÔ´q&žÝeZi[NО–_œÚzRìš#ioòùDr3Ìz+NTÞ<›ôw/E‡óÍW»h|‡½÷›oByôþM»/]~“‘×ßeô|×PØ$B è‚;ã q´Q_v>´!’¡GÝ…HQˆO¬4à,.ø ƒÂów-ÆØ¡7Vñ⎊”H“Ž>$$Œ4©¨R‘F¢ÓV$ YB)Z!¥HId KTvdå•qÙ¥`™”DeY’ˆc’Y&z•–‘˜h¦¹‚™^ÂçŠ=Ôæ{ò ’’¹Dèæ~9ºà¡»åð§“J4 ¨ vš(‘eFµÃRˆ©%¦â`‚à¤+‚Šƒ¨×è¦V \pÆ4–©ÕÕ†—nDñF(®ÃéºkxÀ¦Þ^‚†©šx¢þ¬£ÅrÚYdÂ. «~´Nzš†Â9(í¬õMšUÑɺm¸Öv[Ô·Í’ë¬f¤qЧ±Ï2vé¯&B[ï…y.¹o¶ÑòK'ÀEþw-kýêkIÁôV7¯Áøëaw*pq/œpºí"ú¹§QZI‰ ráµëWDY"áUtÙ–Ìuïlúü×rH‰µôjv&ÏœKýyTš©«™Po†Ôôªš³Ž=ÿu ËZÉT VÕdZ¶›×§\Ÿâ,&æ¤9t%‘%ó¢Ð­îrÆ£i÷g¦­Hç½¹r/'Š”þ¦¤÷6Àq¼îUõYR“2z†Í l³Ï#AùGê"«{´¶G Ò²}ª~2Gm´° ÕýÛ‡1ÎË‚÷ömœ8Ë•'Mb:´ä¨’ùYü+«qv§Ï›E÷¢7yöKÞ·©îõa¸ß³´ºx2uÛÉ÷mëéüö¸ÓþI>ToeÍVJW,­@‰uŸU‹E\/+•R}Æ%æÙ‚¢CÚGˆ˜5QƒjÌ'à€Lx¢`‡”3‰ˆm§XQuU„áÕG`Š*Z×b‰7âe™e:õxaŽM¹Åcn>*Yc^aMµä€þ¡c€‘Y¨’¶4b‡.ÖI“ò™È$™liéÔ†\iæ–ÄeØŒí Ãæzpù5–y×éYæ(Íi…Ÿ‚²˜`¡Ø5ÖÚp¥:Š7¤pâÍ@ qÇaæDŸ”â†å»]ùÂn–^šG§:¨ª´EI*F¬¾ë¨5†A²zÊh ŠUa'¯|åªÌ®lr«QbþìNÆæ§Ó”O$(5üfXu/ŽRl§ÙÖI™>ˆÙ(e•i]é®f*‚,YÙí²gõWQsá®É© 1ûe›ÃÒ¨ìc^ä,®¹£BÿKYµåÁ·/˜nii¨¥z0»DñEn¬[*¨&wÏŒ%ÀñBûU@…Ü@W†,§¼f óÉ`éÓ²ËǼ1~Û[³4°©É"Šîü Ð%oIk«ŽB_9ó<¬´‘ ¡Ó ~DGuÖZoÍu×®õìó¥`‡}ÜØ`ô¦ˆT¾Ùjžï‚Ìpo˜¤.Û‚¸'…+ü³›ÄˆUÛþødÜóѽ !—½0áØ®Ü7¼EÕ’8f·möÕFd®¹×žzè¢Nz馟Žú œc~9©«W(ù„F+Žì“'ޯܓ÷à[àºËSÅšÖ¾{nþÎøÚ7+®©åÆî7ß·cûò¸_¦»˜ÍžUÅkÏ{¯Ù«­·ãØG®øÁÇ·‹éج»ïzæ©ÏOýößþúïÏÿþÿÀ p€dA;galib247/doc/images/GenomeHierarchy.gif0100644003643600364360000001554610573535471017225 0ustar mwallmwallGIF89a‘ϳÿÀÀÀçççµµµŒŒŒsssRRR!!!!ù,‘Ï@ÿÈ@å´³âÍ»ÿ`(Ždižhª®lë¾pC1t Ý€PAïGô„>c.˜  B™tJ­Z¯Ø¬¶jÐm¿à°xL.›U¶ zÍn»ßð¸|N—ÿêø¼~ÏïûÝ6g‚ƒ]„‡@‡Šd‹`† H—=^:^š4P‹‰ ¢”Ž•=6ž¤¶¢’Á^¼È(­!´¬±F¼ÒÈ»ÉÇ>§ÚÊT’àbªc5ß&Οã&Ó_?ìeâ Ìò/öÍŽ"Nè÷ƒöÍ(@ÂÀ?Hô:˜À 7u‚ò S ™ÕVF#”ÿPÈø¤#Äwž„Ä+v¢Ü$cî€ùÁ‡Ì›â”âòC#!v‘åLÇC^ ^ 4>þj0"SM xXƒà“¢aÅ"(J¨;¡žnA½ÑÉ'¨5œAŒ""ß*‚!.f„Ñ™£°’^* `dN•…,+Aï3a´`=õ‘5-SOPNAuËÑQ¹ÞdèÜ£§‡Ÿ"X’6ãn„ÍWÏó'»…騛…ž@—X/Ú¼s­Ú½3÷]×<2øó}Œ˜ çÊ¿ çM—Šo F×fq›ƒqŸ·p`ïAlkÎÛ”Oîð¯rÅ„8 -‰=ôHŒºc·&^}â‡ÿsåa×/ùmdž|›Øxúé€]#¡QA0HäGL"éQ Ÿ]4l³mÚm§Bw|gâ"­¥öߊ”(ÁRÂÜb‹)Û4ÈIH´ì5RRt CŠ)/òWx0*£b¯%¹ˆŒôçd”Gr Êš¦D,]„d šu´_ ¬´•!˜8Rn ÖEÓtM&Ah¦IYUÎÑE4ÅÀMdSʆ¢°ôY‚'§ÄÔâ °¼h EDRZÍ‚ Pm5 ÁòÌ`[u1Ò…ñ…Y¡ mõî5Š`PÀ5–ç£ì,ie‘´æ*Ó º¦âhBö ¥³`挆±µe#?ÜYÿ@…Ô_Pu¡1™FÌ{d¤’0F¨#Ä#…¸lÅ/Äõº¯î²h¼ôÖo½¬Šï¾ÿ°Ç¯"óþ+°2Û>““;x1%Aš2Ö¹™u %[]ò•µ\‘i%Ey»ÐBaÆÕCQQ\.T›^â1WÂÄZÅR# ²Fb9¡Ñ(ƒ4Ç­¨l*Tƒ̪0ÎtU40´P\‰·o‰DV³,õÔ$´IõÕX<]Ö\wí.Q¬*ü¥‡(ã²-´¬+ 5Z©#-¶@¬N°z#¹C@…‘©‘U­¦î ÷˜†M`ʯ~ZÛŠ/Î8ªCPˆbt%I_ªä-4*ÿ”^wîy8..úè1qNúé¨Çz½÷¦¾‚Õ®¿`:½­ÇŽBÀ¶Ãåã—E§_dZ£_Õ䨉^«_Áká›rY SefYµäJÆÐëd^*g`ýÐE°µÙjAF:´ì¼#™T£‰a›c ‘ÇDÄî\îš{’þÖ¤oîÀ"Î$®üóÀ:°†;&í/]cJÝý,ФÄÆuPºIÂR¨²Äl!šùÄó×Z<£KÕÚËa¢9¸!#šH›£Æ{#GAÛ !¤P ’ UÀ´A¥`Š+dÃÈ2# ±DF~LxØE7¶ÀMZII^oCC@ǃÔ2ôŠå6jÿôÈá'ˆÆ 9£‡i£„,¨¢D 0ž±’W‚ÙÅË…LWîÄ—.2)wvtGÐÛ-p~äÀSÈ^ ²yˆ#ˆ§Á$æ,êhŒ¨ö1`ŽŸ¹ÜÒôV7’‘UcU¹Fñ…)n ¸‘cx:¸ÀdÉg„y†·˜õ·x4K‹*ëŠÉÈU4ìYDo¡Þ¥®ŒòOáÚ̪PFêê‘„a™M@)0‰¢F!‘Q~‚Àf7=pÈ!¬3;t$ ßIWÒS ö„ÑòðbçhœÑÁå°â,É$—)Õ'¤9µÈ,T 5BªîΤaÿc¡4¨¨F¢¹yÞ.…3ŸR@¢#d±-EÙ¢©`=A’­KWÚAˆ~ìO°EüþŽ|EÛD–$ç!u" ó‚@!žà,5Aq+|ŠÚݳ®IäU±fÕ­b Ÿ^=]WÃÚžf$íƒ7ðÖ)€à ­b)ÝY ·]î,p¹(ËÞÆ’ñ”+IZü²¹$üi\ZlZ@¨‚hЊÍÐÀRB†zÀ¡åN(`ÿp~ÎcŸ %G@’!§°> ]¨¹ /o›Zò˜÷µè5GeÓË^Û]%Šâ…œØΤ€O&a”på0Vâ3@j¯€Y$‹ÎÅì":0…o7ᬄ‚ÕŃ30à ¯(¨’¡—lV>O®á{ž<×ßž€ªÝºÖÂ(N±ŠWŒk²øÅõ;1Œg<%j‚â8¾±ŽsÌãû¸Ç@þ±ƒ d"ùÈFN2’—¬ä&3ùÉEf±‹iÕX¯>Ö²S~T•· Vôf9P[¾*Ùûå)…ùžWž,”îšNJ$x’%HˆT,7JVyó|ÜnE ¡,Eev‹Ê?v7þST¶ÿGË´HÒäÓ0æáÞf¾RF é¥"5%Õav®¤´+Wœ«HZäÌlê¢>»n O¬—•‹y܃¡‘7î"]dÑp/@e¸n±Ð[«ÑÅÙ&hN¸VॉhM Hœ“ù@%ã‚®®ì÷j}úô…m§'ԌӼš;¯\d¹Ï}n’°›Ý›²LßmîÐûÜÈ&étÍn7›t¸µZM Œs ž†'h8 zøf§0xMsg4¥f›Û8¿º ËšÒe0Û`ÏÞlC`û…Tv[µ°)JvÌKa¢Ká0…μ|[ÙéCjݘ¶0¥)Á®8]#ÿ®. ÔÀ›™ 8ÆÌÍf¤oa öº ‰5—ÁÏ‹7…2;IÀZL,B9¼˜K$Ûà[¢Ò» pš\Ê…SÈ&ŠR´Tƒ8p…সɜ.X†ÒãowNBŽ;B›Ùù4Ê\D%Ò"HW âá°P¦"àƒN„1zOðÞÁ0ð«;{¶ÊxüsF*Že„‘דv`HÞï¸f¿/Þ¯¨öèuìÚ©{…˜_¾7ðïéz5_ù7Ÿ,‚å°¿í*_E£‚)áfœqœmÆ£ðpò@:a`ºá?P¨€ÒÕ¦†7Z.'ò@ÂÂMO5$c•ÿ(ôß×ÔP6å×T2ºP4[SÏ·ËÇ@hÇ {ÑC<…†3Q 2Ô£*c#ÑW6òCa>“5RH`@|ÇÑô'm±.[tAƒÃiñ04‘TNeqÐSQƆ*·V £9Áv] 25$:åA¯Ø)äÃ)䧈)‰_(†‰ë€!ä,ô#}ñ s{1R`AR0.Aàó'¼@$»¥ƒ‘#y\Ÿ`!t†OÛ´*­ðµv”öÝ¢I³ MˆJ4G‹Äàs‘/4G{ IR ˜E äg[„´YUP wfô$n7Y0³3#_òñ >CFèòH1íó)”QLuÓ)aã*rAMõ \Vx\È^Þ%[2t^ä×"‘Æÿ.Èõù'!ª€bÄñp"Y*)…"4–+_¹N‡$ûÍ&¶F~ñЈgR Ç-n?'ikgrUeIˆÝ–,IQ*ÛBvİ`BS7A'”‚Ç€ÅvÄS#DSQuÓ2LÔL9ƒ*ŒƒÇ¶*Ñ„ ð;—M{™Mê7$@‘o’ø‰nÒÒá‰H š”fcIeF)fÜX›¶Éb£©›»¹b´é›Â9œÄÉô‡ A&Ü'™ù1’LõpÁæ|.Ù—}ã‘Ûc^øçTæw^è‘b=“É&Së_÷‡•FE-ã*ÒÙTK•qØy^ ø<8Y†Ñÿ(WâDP6‚ ižWwq 1´‘+ñ7kSwa™À<:j F*1ãy%¶ù …#JOD* !$À07¸ ’ök„ÉÄ)GáfÕ;–3jÊâ£PWœc,€¡¹ž6Ú£YЛ>¤ìœBZ¤Fz¤‡¨pãbrã’âÒ¤Šª˜1a³X1$EY  2¤`Óˆb¥\âL”0SŽ.ФîrNÌ‚,“¢¥™7}Ñ%~³ Nau‡Q,J8VI=²pBà$Q€Ch1듦ÙȦ:5g4 ™ÔI·¦‘š©¯D©Ö·3÷Q”‚l{’ÿ( ¡©¨j{œÐW˜#izVëB(—io!xÞ’ª¸ZUa"I){88ÁHi‡=ʸC¹z¬Èš¬d€©ÊÚ¬ÑÀ¬Îš¬^­Ô:­Ôê¬Öz­Êš­ÚЬ´poà®â:®äZ®æºk皮꺮ìÚ®îúnD™bÜŠ]öZ@ YózõjY÷:‡Ðª(¹n-‰eÿzû:Yвbù*në¯YÓ°a8°cH@ëX‹¯¡³„÷Ž„ P~ã³R,âož)µp‘²'pF¯PàF+LwFÿA2FWu*€is/»SKYÔ‚†ÃrNP£ÂRg U¾øY‡ßRnQÿÓI IgÄ,‘Òô­Ê—GÁ¢.W±_›_]±pÌæ}q±²±f´¨S°è[u· €6K”AM„Q‘áÄÝö8tV¡z(I„e#'tDÙØ’h”'yÒÓ8#ˆš»RŽJwë1p¢Ìõ%¶f s ·Y:.ã |B2ü‰U#he3`C1ÚzÝv%¢6Íó#‚[¥:‹†± P„Ö1Š[wUNØm!j A¶ØÓA‘ç«« _ž¹1MŸ ºZP°. ±~ò™tĸ†8¤[½þu5 °,–°*ÆmîÂqÝë:ê ú¹[v ¶7tðu°G‘#IHÿ¹ƒ ÷׿@¤ôªþ{í1Àý;Ô #?aÀ6 ŸÈÀõq#Àú †« ›ñ²…Ž[MÌUÌ~;{:ë»Á…ÐÁ3 q¯ 7–³H–!L:ä ì &|—p¦åIty!Æv¬ Ä©‰¡R¼)€¾–$œMl{\2S7–„ªt>Ã\€Us2á‡#„Iå0ˆ§ñ C-LHí²€üÀ†U²¡Ã”üQx3<UˆÆ La)ÇÖ‘Æ]ç2ic‚X7U=¡Â7ð·»Mꉔt„— ¡·‰H,ÃMt35¾Ð`,Ø8ÌqÇ¿Ñ ~!ï9ÿ‹…1òÑY¿¹ÂÃì·ÁJÕ2ï'·¾µÉ*Tþ«š¿‘6´üÉkÜÀ«|+@ác4Q‰¡Aá3Ó-‘S‘éȺ³°»ˆÑ¨ð ÚFƨIC0I#z6T,sÊ ¢LJÁ)s2^‘tÏì-$6JŠ&nQ2€†4=#17ò1S5J\E9K®âÀhh1¦’(Xœ3Eáêèag%9öeÇ—Æ0¨X1¾[Æ«p'¨šTΧ„¢\«6(”@ ÖG¡i*=žxjf“˜i¥¤‹ÐVQ!éÒGu‡lÒ|¡Žy&($kTÅÄÿV èÏ„¥A˜ñg6Ä(zŸÙÝ/  %ôT¥FY5ƒyˆÝwB‘CM8«âï-ð ™ì×®?í Ø”®¶–"¹\˜­·È‘Ä„”¾ŒÔî`½Ô-e«CÁ ëo—gtûi¦†mÉ\ž%jöéód3ÂÝzÊö¿õ”âÌm1_}ÿg`¾½’O´üC)bä)eCfëlárk6£EÞ@\»Ö-_±E­¶)NÀÖÜw._A*r3_Òe¶!3)&ÕiVabÏðñO¡b•á|um¸SÑ&³2Éz{‰ŽÿÑ$átWu-c./sE!È£Oa³‡µ×`>w‘*é$çÖ ¦ojÕÉ õÎo³E‚·Gøžš.€»r~éI?¹#ÞÃ=7Œ¼°º'^ð–›–z‘ÏÕNwQ|Q\™‘¬ðx¢{W¦Ÿ9“b‰B ®Ø8Sä6(ôòü1ÎÖè¤tJ%ޗ׉Í/.¥7Ò¿4s6Þ€ÿ΂̫j2 U-}'Œ2Î0%¡ª¢3"ŠŠ£By¦kûÆsâý…ÃÙ`ìñj¨^Ì'{Ú˜L%#˜%¡¾©C0`yO­Ô¹ä‰‰?ÉÍ&áPµ>sÉçxÔ^¦«ŠZ#,4Õ¡?ñ«±´z©²$û¦>È쥱4ðh%E‰ë—¡ºÙE2´B¼Y-ý0 í˜ù6’oĨ€SG¢Ldñ–[L EgœñEšåFo´qÇŠdô1ȱzR ‹DR*"“jE&ŸTÒI(4kJ+“ZòJLŽÔ²Kr²ô2¬*Ã$³®ÊÄå4×d³M7ßÔ¢÷ˆaB”#š¹ …hÜðe ™T£Âj%”A©jK<áÁ…#ŒQË‚1‘8IQKð´Î4c%¾ “Ì‚8U¡…|‘I¼›îqÁ X07|¼SÅ=OƇ¼ÿq¿#§¼òH&·ˆ Ü^@@`È‚Mc¥k'@ÁÓkyb&åÔ~ß&yw,v u&^zÈvÇXh}‹eÇÈ=ü Ž©M¹t< ,®•Ʀ1·†âàg}Eû†0²£à `úB/ÖìµNúTt?ÐX`¢Ðͨ~ñ5p1ÔP>^¥bH‡¯ÉÖ*`¢¿•¨ä… Bp¦åá%pšhô£,û'a$P‘r¸“1Ä.¢¸A7ã…+.¥K‡òÒƒa C<ž²a š &¦aÏõJWÄ'>„ˆ,H^醈E'êЋfšÝ“";galib247/doc/images/ListDestructiveMutation.gif0100644003643600364360000000026010573535470021014 0ustar mwallmwallGIF89a]€ÿÿÿ!ù,]‡Œ©Ëí£œ´Ú‹³Þ¼û*°Œá¹$¢¢—ºBð×r{›Tð ï™p 5 ‘‰å¡Fr” jÄú{:iO›mJ”P[³Õk$ÇLlŽÍνåw¤¸ ˜^;ïÈËžn®øpG>=ô–Ô20¡ Z!.¬xP¿þ|‡u”uocHŽazÂJ BTK‘Z‰ŠË,[Ò|©ÑãAŠs–ÜÙä4‰×lb4yg’ÅpK6ÅŒ¯¦?&„JÓÍ;¬ú–9ï6®WȦ0'N+8´iEž3Û–§7¶q‡¾­[îåºx5´Û÷ÆßÀ„+.\Nb¼ƒ×mìx-»x‘uà;\yÄÉÌâ s>§øó܉¢;S- 3jªWóÐÚ5SÉ¥ùž°Ý9¶Ü´ÓòÎ[æ9Êu*• ‹œ¬*¹7/w…ån¡XéEûhwÎÑ”ÙòÔCù $qã'ž 5*fÍOÞѳšyž”Ïdz‚Ï7ÿ¼áwˆ¶ìö7 0ÈØó}Ni'U&üàÝ3 Š÷P-v¹Áƒ¥]Y ¸Npê ‘œƒØtÈUyü¦™n= ¸›Š(PfÜtYy%b!Ò˜ÄlFä§Ø… ‰ŒUgb:Ú‡ƒ<¾ O©ˆeC‘sT‡=î„LhNcTQyyåí¡—ž^cnÑL0™òeL+íã“•÷a e𝠅'i#U•§Z\&8ÛÌ šJÖ8¡HõãizZ•Ÿ®¨Ôç£Êí÷aY7ºd;%Ê(E[,®è"¥Ò0*© vj«ÊÆÁ«°ÎJk­¶ÞúY;galib247/doc/images/ListSinglePointCrossover.gif0100644003643600364360000000112710573535470021136 0ustar mwallmwallGIF89aO€ÿÿÿ!ù,OþŒ©Ëí£œ´Ú‹³Þ¼û†âHrP¦jw®îKµðL+r‹ç}ðÆŽŠ%à …LøZÉ3t<£FÌŠà]©¶d“±­f¼Pª‹ä*Ñe)Û'žlôÝ»^¿ã‡ä¸…¬evçæ¥–5è÷‡Æµ´Qøè˜xQ”¥Véd'¤9 × cJšYŠC· ·Ê™ù¹€)Õ*û ¶æÖ£ÄxèÄ‹û™Û+| kcéK|l̬ŒÜ ýl«»Çj}‰ÝÅ]m-ý;½ Ü#>Z>NŽÕp)ä¾ÞÖ®îÎN¯Ÿ.¾OÝÞŒÑ.€‹á{—oÙ½nµ,±bHdÖ;‰`(²è¢á©þ?r<¥ñc©"C‘œx²¤Ÿ(©TŽ”ç²“!1QÁ¬¹ò&N13w®¤Ë'…4…¦PWÔh ¤Jyêl:T›þ¦Ö`i5gÒ¬=låÚÅ+Ø1_Çê(kÖÚ´¢~‹x2hŸ°I¦Ìã9qzÒ[ûÞ}÷à!”j¯ßÁ€´m÷mCÉ‘ñÌó*ØÜ´Â—7+æŒxCãÁ‹K{>œÐð?‚&$iÎk°/k…±J¼VTîEº¼›ðÍVCÊà-]eƒ¨*wÝ«¡ÿêzþeâ]YÓv&L:Œô>ßä¼^ÚŒ HÉÛ2_å1e‡Ü iÓÓ¾º‘ž«ÿŽw} =2ýó0›¸F‘Ø ‰GËqo%p cFøÇ„Šrá fÈa‡~¢;galib247/doc/images/ListSwapNodeMutation.gif0100644003643600364360000000045110573535470020235 0ustar mwallmwallGIF89a€,€ÿÿÿ!ù,€,þŒ©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî Çò Ôv=çšÍðúï¸I|@ Ñ‚+ÊŽ;¥‹Ù8SÐtZJ𮨖Ö}QÜð¦¬B›‘jòS¥¾+ãç|Ønåïˆ:l'¸"È×ã÷„Èw3H7ǘó©¨W YÔ˜!Á áùÚ ::ÙgšPÖ¨úY¸Ú +øz  ˜äФ°·;êKû›Ú ̨œ¬,äÚy ]7íL\-{<¼}HìË-»=þ]Ink,^þ¼®ÞÌkþnp˪mÿy½Ÿ¾Ú+8<—l¡²w×AR‡ "th(¢Ä‰+Z¼ˆ1cÅ;galib247/doc/images/ListSwapSequenceMutation.gif0100644003643600364360000000062410573535470021122 0ustar mwallmwallGIF89a3€ÿÿÿ!ù,3þŒ©Ëí£œ´Ú‹³Þ¼û†âH–æ¹* ­lä¶«¬Ò/Ow°3{¿` !˜0Ö?œÁ+:€È'ïºôaÓm6(m@¹Î¤ëü}¢ÑÞõ¹íž)ãé#ýðª"¨Ýdwþ‡¥§D¦å'v¥uh¸7E8ùèÕçˆh•X†Y™)FÈô99v¹é‰G‘ƒ3³ªZçÓ ú‹b{‹›«»ËÛëû |’*\œ‚Gl¬¼È¸ìÌyú,Ýh9mÝ|=M¤§ œ¬6ëýÛÝ=Þ[e~Λ¾þÌí.Ý£Ž]ï|CÏÞÉŸÿÏÚ¾€ <ˆ™83 ÷ÔòÔP!=p°"Vóæ,lKmõc‘PLÂPóÈ(4‘È(™"9ÒeI†qFÞÑG§NNH;áÜÄŒãE”ÕT’Ú¦™´˜%ÊqP¦…|² ëC;²´Ò«¹«"’eeÑÎćצ¥H+m¹tëÚ½‹·n;galib247/doc/images/NCubeMigration.gif0100644003643600364360000000070610573535470017011 0ustar mwallmwallGIF89aMM€ÿÿÿ!ù,MMþŒ©Ëí£œ´Ú‹³Þ¼û†âH–扦À²j $ñÎ2ýÙŠŽg<òëY‚¢ða3ÎŒG /¨s5ÒÝmÇ|U‡–º¥…»e¶Æü©ãw™…Z‘ðÖå)‘ÏË׉žÍð¸ÇˆdHuˆX˜ðö)ùÕpVT9ب¹Ù§ÈÉ…úI¡$:JŠêè§çI*XÚI¨šº…7äÕyÆëf'Bùz*œc©uÕ–Šõ¼}·ë´h݇»œMµ†=ç½Ý\Y•äîÓ]šì›Wëç|==¤.?ƒŽ¶.mÜhµqä¢9K2k ("aúz¦ì˜´K߯›H1cŽžf¦Øä±ÆÕ¡>ta,ÒËSC“´ua7ŒÖ¬ˆm1“˜Ðb=zNbåÜyR'1¡@ƒíÈH&ÑšK™mšf¨S¨ðNºŠÒ¤Oµäs˜2Ÿ]ú1 VfZ_9|ÜNj沨ãÈ]Áð¥VdwAÌ3ûrŠ 'ICˆÈ°à©^ãìêøgãÈ­(SkYb_Ëo2{þ :´èѤ;galib247/doc/images/ScalingHierarchy.gif0100644003643600364360000000335510573535470017365 0ustar mwallmwallGIF89agc³ÿÀÀÀÞÞÞµµµ”””ZZZ111!ù,gc@ÿŒs€ G\ª­ÿP _ `Y)fë¾p,ÏqA‘t®ïÞÀòÀ p8 ¼¸VèUq –Ãh¬xLš ­fk• $q‚€‰`„i Õ…|aMZ©p(â®u«íz{(MF^'%bŒt$e‹‰F$b’“ye{V%~s¡Bzcž'mƒ>¬vt³©ZEH¬tK»¼tÈu·Å«œ¤Š™¢ÓÓÐ»×Øe»#É!°†ÃÙÔèéêÓ۸؆6€À¯å«„§6§7áwÿ¶9ªDŽ‘ OMØ…aŸ± ‚èhˆBbóôUŠc#Ä¿>ÿ!„b'â3V« Ø)çe£ 4鬭›9‡ Í›¢dZࣞ«pÑÈ”PZZˆª v‚"!Oƒ%Fø“úÓQžW„Š•à¬ØO.‚I`5b11ÜQòAÖ¯Cà…E'ÖǸȌ© ÷â«Ñ±ˆ ;)® žl>“°è[˜ 4&àŒã’WˆÀ²—5°À[Bç¶6pP¸c†IÄjÊ 5€ 70×"Î:ú@A'Õf è®…˜Þ+Vç>Þj3^ÃFÅö€PÜx&¦ÎSF(¶O!úZÞS1º7è)!b‡Ú†‘DP€¬P‹ÿ<´`µPÒÓJÈqÆJ.Í„†oÊ Y…Ž¡[†*Ö‡O/<Áaaî¤RçlñÈ^•X” ²¸ƒ‡=1‘–l×”7ÝèY¢IÔ˜ íDš 4†ec 6P'QmÑ£RDÁÌ¢RIÍ¡¤•–Ø!éâY Ä(cI¢õ‚4Ó ™Ó—'*uQþ¤§`xaˆIñEŒfhåÑ\ÆÈBb0ž9Ä"jj2I¢aÈ lè7æš„ŽÑ :îB·™áNWåb‹•–€M`ÛÙ²T=ü‹~ß$#@ADÚœþÎUŸˆ´k»P‰è:‹N,È@wG‹ƒr”SEM–=K„ñ ¬]¶c'¤ÑAH>î„ÚÚCŽË¬hkÙk“j"`oÉg2Z2_|¥nàè Nx5óN©â7­ÂÛãG.ùäÛA¹vÃ^XJÿ¡i¹÷µŸ{æQbšPÌßlržÅ™üfˆv'ªÃƒßjnV›K2ÞCè&Ænªæu“»Ž|bmZ¤%~Dêæ¾lˆšƒ.¸ çѩȱõàC=ÛzÜ¥*Ùy‹$Gm9rÉ"Û-4fŽ”þJÄj ¶7ŠûøL>wºÝ”‡0ƒ98ƒ„ˆ 1¶’Ù3x÷¢æáEð±ójäîu›s î$>3eA@;IÁ£¦ñø$~<Ààí|—¢ „c„µˆÿXNÈC®w²a‚â{ÞI´a‘5¬Ov±‰J8‰Œ±jûð2>6F©Ð~,ÜNÆåmÿ¬¢4¬1tí<Â!={E¾þ· zq$ËG×Â ÚÆvLáÓ‘Çü¯j°`£*â‚Ó±‘~x¼˜lbñ¨ú€/9ú^ƒã hM D*yžÕĆ* ÖM×Ã#ng~¬ˆ Á†Ñ m"6GÃËâ (d…;63ˆ^ÊR?Ñeñ˜ •@ÐqÔ;Å Wª‚Gø/;ò°ÁÓPRŽ8.°ƒyL‹E碚e3ßDG/õa˜H&og‚ ß®®•ƒÌ²2Í Á í1’¤|ÓKGFÆyÚ%6­5–']¡«E 9£’|ÉÂ-_LÎ8“Êl)š7ãd×F&•Ñpzô£ õ Öˆ˜ Cˆ¸*VLê7l$-–XR²A3|°2•p=çÁÅ‹8ìAý Ã>ÒPó!c_òìÓ=†•JU‚¸ÃÄñ1>,•j|öòÏ ´¥=«ê§)+mô/I+†ª(ÓˆIä3mˆ&膨C\ se+ÛPÓ…yæÕN¡rW]í*†¸F;galib247/doc/images/SelectionHierarchy.gif0100644003643600364360000000420710573535470017727 0ustar mwallmwallGIF89ap³ÿÀÀÀÖÖÖµµµ”””ZZZ111!ù,p@ÿˆs€F\ª/†'~@AŒ"'‚hë¾p,Ïtmßx®×ùÿÀ ðÖs®Œ«²t‡ÐèuLvPÌV–Š´®ß«K<õˆ£²²¨ÚRj_[´\®ö°Qnl«P!0 >q)>^}q0€‡K/uw#y#†s¥¦ž "¢£H™~~G™€ƒ¼º|!ƒ—œ‘Ô:©«v“§ÝÞ-ØÚ¨——'˜—ãL‘èíYÎÎí®ï ]¾9A$° A=(ã£/[¤@‘8MVËϹKµ"YôCmŸeœÿÒÃÍKIy%ôpR¤Ë’†Åcôa >ÌA¼ËÀ¥IŽ,«é( ,•2–@R´ÙËk ŸJ5ˆmªÕRáV²:£Ž“W±Fý¤ÕC«®MôLËöÌ4&·"}xØO$v‘`éŠÉÔÖ8gC²ZI¶0ª±ªÊ^8ë Kˆqv¥ó Y†s(ûXV9¬ó8>ËÕpËÒ¿ ¤CkèQÌÖÄ@°Ql±áÛ·áª*’ÇC‘Yà#6;yœ Àõ;Û#N1Ô,QÎZô**­®.lÝ£T8LÔ;õó3.)[AênÙ-ĽŸnìzçÃÞ¡ºì¶Ÿ:  !ÌÿP4 Ãu“  }4ØÃàƒ7ĤÂ]ÈRÝ}Ð4 $E52šezá4 0‰3ú}T°`äVħ‚ ’™Ô$Z³—‹ÇŒ¨4‚Á^Ô­‘$v15…Dô‘¼ôå[†¹mô}áã–1TÅå–^~9¢Ê}aæ# pæ™°&šŽ¸ùÈœnJò¦› Šix¡ðæ–Wõé¹'bÙ`iÛPo*Ÿ[¦!½ÓËPµ<¡¦xÕ†ÄL(‡ ¸Èã;~A¨|”ÚÞŸ(x×’C¡˜Ëgr=äá ,p¸ÔMµfà䢧ª* ŠÁ¨YÃ{ʱ‹%;Êÿ\'èõ"5øüe™O>½Æ–;'ø¤ eÌt¸“oÅèè¡%ÙŠ{™^&:ƒ% Oô–4I€¹À™›Nb¢ Üpп’Û½ì‹ï~òÐûî¨Ú’²h0[o³C¨o ôæÝ‡¡PÍo É8DAîöâÓ<˜à-n›¡±‹¶¸eÑoÌ•F‚#„`sl%Ç',Å.YÌôSÌÆDB0)ö’aÑ— ³2E¼Ø%â5z-St¨£1ÔÁjAå$©Çâ]óT#SËÉåö\ ‰Ú„jRð Éa#ÔÓ…¥2Ë·üȶ‚>>ܤv¼01áž´,Ék¨W7ÿ £ZÚ 5¿vÎ=1å’€û&ᬷ~J-~‰Ý²is¸€LDÚxü&ì¦ëàüÃGå4·ÚÙ÷DËWû*…À£‰JLXá'BÛ¥^/u«2Óàðèñî@¤2ìú1Ñð0ò Ì ÑN?ýÒ4bµºÝîËÌhƱœž˜CC2“ YÔ·Ëô¢/àšˆ–¸T… 6 9ÜÈSdžüÎAð*’¨DÊÄÐi$|TÆ:Š…ƒPÒpÔ³õDBÿ “cÕ¹èÂ+&!Œˆ’â~×E|1h pz(3¶!ŽÄ M(À·` i‰ÒÔH/ Iø`ç.¢\FÒˤ8"j¨'xéÈÙ~`G0j1Zèc‘Bä¡%Éå5Œð]Ž $f MZrbwÈOšÅÊÈr4” &-ä3m 1^õ¼è˜3bá Œ€ED*’޹1ämyó@STÌœæ3¯ Zj“?’fò>®¡whÑÏ÷âó k˜…PH6ïHM©%#G½¡ˆˆ(DÈ„K3Ó+š/\¶ž)¨½ágL8·¯âa"x#+œ Ê™éäÿ|Ø“™®å|È…ÊQ†d8‘ †&‰"eÇc@P”{€´£. 3BP4¤uŽÔ$'/a¶OKR©oÉÅçz‘‘ ò!ŠÈÙ8TH)?òÈ‚7é¹MnÊ3>ÍÌ©Uë(Mªn5iTȪô¾¸°©D™r SYz†Ã®zrBÒÛ:@&¶J¤9k:xœÆ…„I'X’Íj3å)fÇ,€ŽVˆ‰”kÁ\‚Q!˜tfîr?çÁÈ¡bVÈ…hæµeS}ëT¥mªCç`2¢ÁF\êÃÜ9ü —œ8²)Å+ iÊÙ¥S=ö«8Hí(º‡Ün·¹…ÿtã ‚F1Ýt1Õyœ €’-Ñ$`,IgD953H ¼VQ®+pT; D™‚‡^žA=ZÍOê;’J‘‡ âz㺉í/ žÁ)Å÷tê_­Î÷Àü†hµ’R_èV}Á€¹6’Ά’tÃTñâ„¡‹·ÕÄC ¯j³GQ‡Úý´²ÎНr«¥¤3<ç݇#pi„=B$Ià"~#¦Oå"U·­¥#O DH.Ù0ú™)& BGÌ’¬dÄ Oî¡ÎíTÁâO¨zn ÿ*’;Cˆ‡(ÖãLçbAã1=Ò©RG)íšîRöœÈé"ƒ‚ª4zâ’I³qYQ¶Ó^þUž\ÎgÊPÐú4m”(û¥‡”Œ™()™PÜ­g¦;ÐC)›73-;galib247/doc/images/SteadyState.gif0100644003643600364360000000155610573535470016401 0ustar mwallmwallGIF89aæb€ÿÿÿ!ù,æbþŒ©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇòL×öçúÎkÀ ‡Ä¢±‡L>¦³ ­ü ÏjT‰ÍN­S)õ[efÇIîWj6“×»-XLI¿kpHM7ê÷üî쾈7H¨ ˜pX¨ˆä××èäÖôxµh#öt–¥éi y)êòÔiZÇÉÙ9JÒ÷ kʲ Z{Z»JÛ ’š†+§¸¢škûYÌZÉë VéöÛhgi;y›éI¹ìà -}û¬6ŒáÇ‹.ê\žœH½ä})¼{¿—±»Ží€ÿ_¤P¬qZ`ô׋ÜBñ4´ñмÑFäq–þŒ¨q”,›5€$euÔ·¤ºk hE'èãAC%K^¨(GÛ™8Q:Ìõ‰U2aŽZþô)Ð"vÉìó¤2hUÊ‚·AÝœ uÖ“à4ëÑcýp)³"ÕÒA!_ÂÉSãZ¹Au %[wÚ7E5mʽ™ÛÊR:6Ò{nZ_€I+yêQoHDmç8³ÄS¨¯ÒŽ¥i1lÛÍdºuˆÚÂ4âa“¡*ý nŸØž³ú­-îä蛋ÿ¡¼˜wi–ÜŒ…€í°7>ÇЂ|½Y«¿—ÁÉnrwœt¬nWNwè±¢×eÏN§x'ÂÝ*캷ŽÌ6¸Ó’áNmyÄû¢vþËËŸŸ•r÷ß)“lcàT.È`ƒ>A>N˜Úm^hV'8 †˜X¨Ÿn]E~Òy؈"øBS^á‡â f(b;óNŒ2ªxœk\¸H"Œ:Öö™+4$‘j%É$s´5 å3FIåDKV‰å“eÉefžé ]—=‰rbîH&D^žI lÉf›i¾©eœÎù!žvjæ&š}î¹âŸJ"h SÊ\¡( Ga*Jè•2 ¡Øp†¨§Ÿu^h¦rJÊ阠"*h¨{š'ª¦rÀ(ª®zꦤ– k\žVi­çÝ:(¯º úhBÕüê$­wÚqHd²Ê.ËX„`›jÁBkkԻݵ‹j¡-Ÿ—uÛiiàRÄÖ¸¬6fn±x0Ën»î"™n¼òÎKo½öÞ‹o¾úîËo¿þþËA;galib247/doc/images/SteppingStoneMigration.gif0100644003643600364360000000045110573535470020614 0ustar mwallmwallGIF89aNN€ÿÿÿ!ù,NNþŒ©Ëí£œ´Ú‹³Þ¼û†âH–æ)*€¶ìñ¶d Ë#à6§ýžùý€“˜°F,ÒŽ°aÒ×ÓE¶•cy¥šT’•6ÀÝ…Kãí×SîxŸ9륜®.Ï9=$­0ÅŒû¾ÚGñ'3øPˆrxe÷”§7ÇøøæÆ6Iy‰™©Y´y×๥Ö)ª º`:Cš‰šÀš¢ŠéŠ´ {)»‰›«Ëc ×IÚ(¼(”˜|ÌwŠü¬Ì±L6MÝ,Ýj1 Ù†±¦]ù«QŽw«D–Î}.ëÞÇŽ&Ü´[Y·ŸŸ½ïïÓµ€üþXð AzIº)Ìâî¡Ä‰+Z¼ˆ1cÀ;galib247/doc/images/TreeDestructiveMutation.gif0100644003643600364360000000061310573535470021002 0ustar mwallmwallGIF89aHX€ÿÿÿ!ù,HXþŒ©Ëí£œ´Ú‹³Þ¼û†âH–f¤ÀI®‡Ë~ðËÊ\kx°ç×ÞóYfA!e¥B3DÚ²‚k>%@ÔÒ«^ÙÛ–ì~ÅðØPäqÏéò8­^_áqù’^·ûðy})™‚¥‚Å3(õ å "¶ ¦†ÄGéׇ˜©s)iµÆXñè ¶9Jzú‰&89H—DeØâ¢:Dvx‚èèkê¡ %ÜA|äy¬¼<áÆñlÙÚiÒ&ÍŒY|MȤ½øÝBN.ؘËÚ<Ë l¬Îé3ýîZmQ ß6¯ÿ£Y¿pðœl‡/TBæÙ 5ˆÞ„cüZx!.cŒùœ#ðã3õ¶D+9’`È”Û8ƒ d¢™,iªœ¸Ê›¯ˆçØ5´Æ§KŠ5ÍÓ¨Á:þhÄüT©Ò¤¥ý{ZU“ÓtY±ëj]¢‡Åf<‹6­ÚµlÛº} —E;galib247/doc/images/TreeSinglePointCrossover.gif0100644003643600364360000000174610573535470021131 0ustar mwallmwallGIF89a§€ÿÿÿ!ù,§þŒ©Ëí£œ´Ú‹³Þ¼û†âH–æ©*€¶ÔÊŠ±1»öR×ð·Íóe‚¿"M!Ä¿¥ÇÉtAwˆd´”ÁzW`oÅ•U»¨ì1¤³’7é1¨½'àOdü³×õwŽošÂ Ö!ô·ÇGh‘dH%¨¸èÀè' ùRùȆiYø`5èʹ٠ZÚ9š—JZzwúz±…Y{·5x‹º‹z ËŒË¥ÂFjšó) F¼\ýû™hÇ kRÌÜz¼ê– ŽÃEüÕ]=—^‰½¶}î+ní¤,‰]NòŒ^zï/MÔ|ñÞÓ5ï[=AÍ|ÁЧ­¡'‰øŠ}0³° Äþ(t2rTµnÞF- щ¦dF@LPzQhÒYÉF0¸l1)\KUêj6áÙ-á›Úêüi ¡Ñ¡I#Ì*Bô ¿‰R”qÕ¦ÐåytÔU+ך=c¦ •^²a™»µ-Û¯Ð"»pnT»{•àíª´íÅ¿R²Ž«Jµïº\*GaTÜØ­7ȑ늬lð$fd7ôIÙóÒ­¡Eû|k×4I¯©Uã ŠÚõàÑ­eqj̶eÚjušZa/ß ÓLœ5]–±K÷a.—]rÍÊõN§~tyïä½w®h8CÄÁ¯›?>½úõìÛ»?¾üù•¦©6þKúþ÷K€îßÛE&N^tßnàe·`w`ŶÏp­FJv%ý¹ràYÙÍv¡€zØám#ZxÜ>ºEcwAˆ‡‹$.˜xÉcQ‚ˆÜk9åÜ}hN‘|ñø£ŠF®…d’~M®åTbn!r2—“V^ I–;¢XeS°})¢r*·â–'>‡omºÙe™c–gK‚6çyy80É1ß 7€$ƒ‰î‰¨3ä,Š]gÊ™;ÕAz$/jô襞z×I ±P ªQ¯ØIžɘ§,¨š 84’È™8³6¹Z·>øY¦3eæ+H»~¸Ò™µž6À¬_½f˜l~¹›¢LÏBíͦhŠcpÍIæ±/©¹æP¯¦€çxÂ{‚ƒ>bK˜º/v«,^™n˜`j§½:r)'™óÚ‹£–Îþøo¸VKK» ¬ä„XŒËçè<õ¶udñ”ºx¯¾b0}Rò+ßÈ$¿G%À(™ñ¯f2¼2·-‹É-Âë=§z¬š+JÄÜ- ¯»Ó,¯Ê›M°Ñ˜!í¯Òõ ȴͦ m« íùœª«ªrÌu×^m^;galib247/doc/images/TreeSwapNodeMutation.gif0100644003643600364360000000036710573535470020227 0ustar mwallmwallGIF89a5<€ÿÿÿ!ù,5<ÎŒ©Ëí£œ´Ú‹³ÞxÀqà1†WIš§‚ªRÀî˳ƒÚ7~ý)å€8DK·;²ˆ‰Ú©r.™±'iÓA3Úâ­ÛØZPñ¤Ü1mÅf/í5þTiò·/Ý[ñ1r5ï–ö×öó3Ø„s8guè§8øhH¹GɈ٘h°–¹è±ÉS×AšÖIt™Ê‰Êzù+(»j[›UK;…Ûújùû&«|Šezu73$ìªÆk5»!{«AmÍÍ-:­=Ûv†lª{Žž®¾>S;galib247/doc/images/TreeSwapTreeMutation.gif0100644003643600364360000000102010573535470020224 0ustar mwallmwallGIF89a[h€ÿÿÿ!ù,[hþŒ©Ëí£œ´Ú‹³Þ¼û†âH–æ‰FÀ ¤îÓñKËÊ\¿¸±çhßó™€B.X$µXËä1C:;»ãTD„^?ÁìvÓ½}ÁŒðø"EJÏeGš=Y¿áu@Nw×aù…·×g£BHÇôÇ´—¸e¥7¨·ô—â%–€×´2EiYY†y§Ù) Øð™é´©ÅYjzÕXªêö‰Ê³({ZÇú(iÑ;´J ò«4J\(dK•¤üÈœÜ6ªqÌëçQ -Í¡ííØMVc‡7®xñ!‰HŽî{r¨¢ ‰Ÿ‹‹µÜÉç7Pý‚aÃ4ÇŸAaÖZj5á4vêrBXQ¢CèŠ zÕ¤£9…Û<²P£(Ž·zÙj©HˆÃbÍ,‰ó• ›n2g‘M…>Ûeëh2ÇÌ„w’ ªÒiÒ¦QŸÀ›7mÒU¬Yë­“‡ŽK°^%$B¤ÖË~îž.{L””q§Ž¬kÔ­]®w«~õÈÔo*¢VEò=\ðN9½ áú5Š-?˜÷&—œ+•Þ³¢™;›MçéàÐ*‘¦{:,×Îß8Y÷´kZ¨»:Úsmq³©YþøÛOp¥Žõö-c1Áá!ïÒ;Ú9ã×ÒÕ ü؇ñ⌚ߊs=µøñäË›—Z;galib247/doc/Installation.html0100644003643600364360000003362410573535471015544 0ustar mwallmwallGAlib: Installation Instructions Installation Instructions for GAlib

There are two things to build: the library and the examples.

First check the makevars file and uncomment the block of variables appropriate for your operating system and compiler.

To build, test, and install GAlib you should be able to type:

  % make
  % make test
  % make install

Depending on your compiler and operating system, you may have to edit the gaconfig.h header file in the ga directory. It has preprocessor directives set up for some of the compilers/OSes on which I have been able to test. First try compiling without editting gaconfig.h. If that does not work, then read the comments in gaconfig.h and adjust that file as needed.

Here are specific instructions for various platforms and issues:

Be sure to read over the section about template instantiation if your compiler starts to choke and spew errors. Most errors people encounter are linker errors and are typically due to template instantiation problems.




Unix compilation:


Edit the file 'makevars'. This file contains the compiler flags that are unique for each cpu/os/compiler, as well as the destination directory for doing 'make install'.

To build the library and the non-graphic examples:
  % make
To test the library by running all of the examples:
  % make test
To install GAlib on your system:
  % make install
To build the graphic examples:
  % cd examples/graphic; make

If you are compiling the graphic examples or the parallel examples, take a look at the makefile for each one to make sure that it is configured appropriately for your system.

If the examples fail to build, it might be due to the type of make you are using. In the file examples/makefile, be sure that the right rule is being used. If you use GNU make, uncomment the "Use this for gnu make" section, otherwise uncomment the "Use this for non-gnu make" make section.

Some people using g++ (typically version 2.9x) have reported compiler errors that complain about memset not being declared properly. Typical error messages look like this:

../ga/objective.h: In method `GAObjectiveVector::GAObjectiveVector(unsigned int, float (*)(const GAObjectiveVector &))':
In file included from ../ga/genome.h:33,
                 from ../ga/ga.h:99,
                 from ga.C:20:
../ga/objective.h:68: warning: ANSI C++ forbids implicit conversion from `void *' in assignment
../ga/objective.h:68: warning: implicit declaration of function `int memset(...)"
       
This seems to be due to an error in the string.h header file in the gnu installation, not a problem in galib. Evidently some versions of g++ have an incomplete string.h in the lib/g++-include directory. Try using the -I compiler flag to force g++ to use a valid string.h (or update your gnu installation to replace the bogus string.h file).




MacOS compilation:


Set the includes path so that the directory in which the GAlib headers are located is searched before the system includes. Set the compiler to use strict ANSI compilation. Set the development environment to use the C++ compiler on .C files.

Adding the string genome or real number genome source files to a project may cause the compilation to fail (depending on your compiler). They are designed to be included by other source files rather than being compiled themselves. They contain specializations of template classes.

The GAlib site contains project files for some mac compilers. Each of these expands to a projects directory that contains stationery for creating the examples and a sample project for creating the library. You can either build the library then link to it from subsequent projects, or you can include specific GAlib files in each new project that you create.

If you cannot get the library to build right out-of-the-box, you may need to edit gaconfig.h to tailor GAlib to your OS/compiler configuration. When you edit gaconfig.h, use directives similar to those defined for __MWERKS__




Windows:


There are two makefiles for windows: makefile.vcpp (for microsoft compilers) and makefile.bcc (for borland compilers). These contain rules for building a static library which you can then include in any other project.

Set the includes path so that the directory in which the GAlib headers are located is searched. Also, set the compiler to use strict ANSI compilation. Set the development environment to use the C++ compiler on .C files (this is the /TP flag in MS Visual C++). Enable RTTI in Visual C++.

Adding the string genome or real number genome source files to a project may cause the compilation to fail (depending on your compiler). They are designed to be included by other source files rather than being compiled themselves. They contain specializations of template classes.

The GAlib site contains project files for some PC compilers. You can either build the library then link to it from subsequent projects, or you can include specific GAlib files in each new project that you create.

Microsoft's Visual C++ compiler complains about statements such as float x = 0.0; To disable these warnings, insert the following into the gaconfig.h file:

       #if defined(_MSC_VER)
       #pragma warning (disable : 4244)
       #pragma warning (disable : 4305)
       #endif
       
If you want to use GAlib with MFC, then be sure to turn off streams by undefining GALIB_USE_STREAMS in the gaconfig.h file:
       //#define GALIB_USE_STREAMS
       
This will compile GAlib with no dependency upon the streams library and may avoid conflicts with MFC streams use.

If you cannot get the library to build right out-of-the-box, first try changing your compiler settings (particularly if you are using VC++). Then edit gaconfig.h to tailor GAlib to your OS/compiler configuration.

I find it easiest to compile from the command line rather than using VC++ projects. On NT/2K/XP with visual c++, use nmake to do the build like this:

       make /nologo /f makefile.vcpp
Or, to make life easier, create a file called make.bat with the following in it and put it in your path:
       nmake /nologo /f makefile.vcpp %1 %2 %3
Then you can simply type 'make' or 'make install'.

If you are using the Borland compiler, use make to do the build like this:
       make -f makefile.bcc

If you want to build the graphic examples, be sure to download the windows-specific packages in addition to GAlib itself. They are called gademo.zip and tspdemo.zip.

If you prefer to compile GAlib using a project, then see the project_files directory on the ftp server for some examples. I no longer maintain these project files, but they will give you an idea of how to set things up.




DOS/Win compilation:


When compiling under DOS or Win3.1, use the large memory model. When you compile the library by itself, use a library page size of 32.

Be sure to set the includes path so that the directory in which the GAlib headers are located is searched. Also, set the compiler to use strict ANSI compilation. Be sure that GALIB_USE_STREAMS is not defined (do this in gaconfig.h) if you want to compile GAlib with no dependency upon the streams library.

Adding the string genome or real number genome source files to a project may cause the compilation to fail (depending on your compiler). They are designed to be included by other source files rather than being compiled themselves. They contain specializations of template classes.

By default, the library is configured to use the system's 'rand' random number generator when compiled with the Borland compiler. This is because I've had problems with the better RNGs (ran2) in 16-bit mode. If you are compiling a 32-bit application and you're using a Borland compiler, you should edit gaconfig.h so that USE_RAND is not defined. In any event, be sure to check the integrity of the random number generator by building and running the randtest example as soon as you build the library.




Custom compilation:


Edit the gaconfig.h file. You should read the comments in gaconfig.h so that you know what the machine- and compiler-specific options are. You can set these options either by #define-ing the macros in gaconfig.h or by defining them using your compiler's pre-processor directives. I have put a few compiler-specific #defines in gaconfig.h, but I don't know the characteristics of all the compilers, nor do I know the compiler-specific preprocessor directives.

Be sure to set the includes path so that your compiler knows where to look for the GAlib header files. Also, be sure the compiler is using a strict ANSI compilation mode.

You can either compile a library or only the parts of GAlib that you need. In either case, see the listing below to determine which files you will need.




Template instantiation issues


If your compiler uses the Cfront automatic instantiation model (code repositories) you should not have to do anything special.

If your compiler uses the Borland automatic instantiation model (all template code must be in the header files), then define the BORLAND_INST macro. This will cause all of the header files with template classes to include the associated source files. If your compiler uses this method of template instantiation, you do not need to include any of the template source files in your project. These include GAAllele.C GA1DArrayGenome.C, GA2DArrayGenome.C, GA3DArrayGenome.C, GAListGenome.C, GAList.C, GATreeGenome.C, GATree.C)

If your compiler does not do automatic instantiation (for example, g++ 2.6.8) then define the NO_AUTO_INST macro. This will force an instantiation in the source files that specialize template classes (for example, the GAStringGenome). Note that there are (at least) two different syntaxes for forcing instantiation. The GNU compiler likes 'template class' before the forced instantiation, but the Borland compiler does not.

The symptoms of no automatic instantiation are linker warnings about member functions not being found (or defined) for template classes (e.g. GAAlleleSet when you're using real number genomes, or GAAlleleSet when you're using string genomes).

The string and real number genomes are treated differently than the other genomes in GAlib because they are specializations of template classes. They are not included in the ga.h header so that they will not force instantiations where they are not needed.

Do not explicitly compile GARealGenome.C or GAStringGenome.C! These are specializations of template classes and should be included once (and only once) in one of your source files. If you are using a real number genome, include GARealGenome.h in any file that refers to a real number genome and include GARealGenome.C in one (and only one) location in your code. GARealGenome.C contains a specialization of the one-dimensional array class, so by including it in a single location you will tell the compiler to use the specialization rather than the generic template code. The string genome is also a specialization of the one-dimensional array genome, so to use it you should follow the same guidelines (but include the string genome header and source rather than the real number genome header and source).




What to do if your compiler does not understand templates


If your compiler does not support templates, get one that does :)

You can compile the library by defining the GALIB_USE_NO_TEMPLATES preprocessor directive. If you do this, you can use only the BinaryString genomes (1D, 2D, and 3D). All of the other genomes are implemented as template classes. If you define the GALIB_USE_NO_TEMPLATES directive then you should not compile the following files:

GAAllele.C GA1DArrayGenome.C GA2DArrayGenome.C GA3DArrayGenome.C
GAListGenome.C GAListBASE.C GAList.C
GATreeGenome.C GATreeBASE.C GATree.C
If you need one of the template genome types but do not have a compiler that understands templates, you can modify the template files by hand. You will have to create a file for each type that you want to instantiate. If you will be instantiating only one type, remove <T> and replace T with the type you are going to instantiate. If you will be instantiating more than one type then you will have to replace <T> with an appropriate name and replace T with the type. For example, to create an instance of an 'int' version of the tree object, GATree<int> would become GATreeInt and any occurances of 'T * var' would be replaced with 'int * var'.


Matthew Wall, 12 November 1996, updated January 2005

galib247/doc/OtherSites.html0100644003643600364360000000307010573535471015164 0ustar mwallmwallGAlib: Evolutionary Algorithm Sites GAlib
Some sites with information about evolutionary algorithms...

This list is by no means comprehensive, but it should get you started into some of the bigger genetic algorithm and other evolutionary algorithm sites.

comp.ai.genetic newsgroup
comp.ai.genetic Frequently Asked Questions

Encore (The EvolutioNary COmputation REpository network)
GA Rules of Thumb by Wendy Williams
Illinois Genetic Algorithms Laboratory (IlliGAL)
Michael Trick's Operations Research Page
Navy Center for Applied Research in Artificial Intelligence (NCARAI)
Yahoo has a small listing of GA topics

Matthew Wall, 11 March 1996 galib247/doc/Overview.html0100644003643600364360000007171510573535471014714 0ustar mwallmwallGAlib: overview Overview of GAlib

This document outlines the contents of the library and presents some of the design philosophy behind the implementation. Some source code samples are provided at the end of the page to illustrate basic program structure, operator capabilities, operator customization, and derivation of new genome classes.

When you use the library you will work primarily with two classes: a genome and a genetic algorithm. Each genome instance represents a single solution to your problem. The genetic algorithm object defines how the evolution should take place. The genetic algorithm uses an objective function (defined by you) to determine how 'fit' each genome is for survival. It uses the genome operators (built into the genome) and selection/replacement strategies (built into the genetic algorithm) to generate new individuals.

There are three things you must do to solve a problem using a genetic algorithm:

  1. Define a representation
  2. Define the genetic operators
  3. Define the objective function
GAlib helps you with the first two items by providing many examples and pieces from which you can build your representation and operators. In many cases you can use the built-in representations and operators with little or no modification. The objective function is completely up to you. Once you have a representation, operators, and objective measure, you can apply any genetic algorithm to find better solutions to your problem.

When you use a genetic algorithm to solve an optimization problem, you must be able to represent a single solution to your problem in a single data structure. The genetic algorithm will create a population of solutions based on a sample data structure that you provide. The genetic algorithm then operates on the population to evolve the best solution. In GAlib, the sample data structure is called a GAGenome (some people refer to it as a chromosome). The library contains four types of genomes: GAListGenome, GATreeGenome, GAArrayGenome, and GABinaryStringGenome. These classes are derived from the base GAGenome class and a data structure class as indicated by their names. For example, the GAListGenome is derived from the GAList class as well as the GAGenome class. Use a data structure that works with your problem definition. For example, if you are trying to optimize a function that depends on 5 real numbers, then use as your genome a 1-dimensional array of floats with 5 elements.

There are many different types of genetic algorithms. GAlib includes three basic types: 'simple', 'steady-state', and 'incremental'. These algorithms differ in the way that they create new individuals and replace old individuals during the course of an evolution.

GAlib provides two primary mechanisms for extending the capabilities of built-in objects. First of all (and most preferred, from a C++ point of view), you can derive your own classes and define new member functions. If you need to make only minor adjustments to the behavior of a GAlib class, in most cases you can define a single function and tell the existing GAlib class to use it instead of the default.

Genetic algorithms, when properly implemented, are capable of both exploration (broad search) and exploitation (local search) of the search space. The type of behavior you'll get depends on how the operators work and on the 'shape' of the search space.

The Genetic Algorithm

The genetic algorithm object determines which individuals should survive, which should reproduce, and which should die. It also records statistics and decides how long the evolution should continue. Typically a genetic algorithm has no obvious stopping criterion. You must tell the algorithm when to stop. Often the number-of-generations is used as a stopping measure, but you can use goodness-of-best-solution, convergence-of-population, or any problem-specific criterion if you prefer.

The library contains four flavors of genetic algorithms. The first is the standard 'simple genetic algorithm' described by Goldberg in his book. This algorithm uses non-overlapping populations and optional elitism. Each generation the algorithm creates an entirely new population of individuals. The second is a 'steady-state genetic algorithm' that uses overlapping populations. In this variation, you can specify how much of the population should be replaced in each generation. The third variation is the 'incremental genetic algorithm', in which each generation consists of only one or two children. The incremental genetic algorithms allow custom replacement methods to define how the new generation should be integrated into the population. So, for example, a newly generated child could replace its parent, replace a random individual in the population, or replace an individual that is most like it. The fourth type is the 'deme' genetic algorithm. This algorithm evolves multiple populations in parallel using a steady-state algorithm. Each generation the algorithm migrates some of the individuals from each population to one of the other populations.

In addition to the basic built-in types, GAlib defines the components you'll need to derive your own genetic algorithm classes. The examples include a few of these derivations including (1) a genetic algorithm that uses multiple populations and 'migration' between populations on multiple CPUs, and (2) a genetic algorithm that does 'deterministic crowding' to maintain different species of individuals during the evolution.

The base genetic algorithm class contains operators and data common to most flavors of genetic algorithms. When you derive your own genetic algorithm you can use these member data and functions to keep track of statistics and monitor performance.

The genetic algorithm contains the statistics, replacement strategy, and parameters for running the algorithm. the population object, a container for genomes, also contains some statistics as well as selection and scaling operators. A typical genetic algorithm will run forever. The library has built in functions for specifying when the algorithm should terminate. These include terminate-upon-generation, in which you specify a certain number of generations for which the algorithm should run, and terminate-upon-convergence, in which you specify a value to which the best-of-generation score should converge. You can customize the termination function to use your own stopping criterion.

The number of function evaluations is a good way to compare different genetic algorithms with various other search methods. The GAlib genetic algorithms keep track of both the number of genome evaluations and population evaluations.

Defining a Representation

Use a data structure that is appropriate for your problem. If you are optimizing a function of real numbers, use real numbers in your genome. If a solution to your problem can be represented with some imaginary numbers and some integer values, define a genome with these characteristics.

Defining an appropriate representation is part of the art of using genetic algorithms (and at this point, it is still an art, not a science). Use a representation that is minimal but completely expressive. Your representation should be able to represent any solution to your problem, but if at all possible you should design it so that it cannot represent infeasible solutions to your problem. Remember that if the genome can represent infeasible solutions then the objective function must be designed to give partial credit to infeasibles.

The representation should not contain information beyond that needed to represent a solution to the problem. Although there may be merit in using a representation that contains 'extra' genetic material, unless properly implemented (in concert with the objective function and in full consideration of the type and characteristics of the search space), this tends to increase the size of the search space and thus hinder the performance of the genetic algorithm.

The number of possible representations is endless. You may choose a purely numeric representation such as an array of real numbers. These could be implemented as real numbers, or, in the Goldberg-style of a string of bits that map to real numbers (beware that using real numbers directly far out-performs the binary-to-decimal representation for most problems, especially when you use reasonable crossover operators). Your problem may depend on a sequence of items, in which case an order-based representation (either list or array) may be more appropriate. In many of these cases, you must choose operators that maintain the integrity of the sequence; crossover must generate reordered lists without duplicating any element in the list. Other problems lend themselves to a tree structure. Here you may want to represent solutions explicitly as trees and perform the genetic operations on the trees directly. Alternatively, many people encode trees into an array or parsable string, then operate on the string. Some problems include a mix of continuous and discrete elements, in which case you may need to create a new structure to hold the mix of information. In these cases you must define genetic operators that respect the structure of the solution. For example, a solution with both integer and floating parts might use a crossover that crosses integer parts with integer parts and floating parts with floating parts, but never mixes floating parts with integer parts.

Whichever representation you choose, be sure to pick operators that are appropriate for your representation.

The Genome Operators

Each genome has three primary operators: initialization, mutation, and crossover. With these operators you can bias an initial population, define a mutation or crossover specific to your problem's representation, or evolve parts of the genetic algorithm as your population evolves. GAlib comes with these operators pre-defined for each genome type, but you can customize any of them.

The initialization operator determines how the genome is initialized. It is called when you initialize a population or the genetic algorithm. This operator does not actually create new genomes, rather it 'stuffs' the genomes with the primordial genetic material from which all solutions will evolve. The population object has its own initialization operator. By default this simply calls the initialization operators of the genomes in the population, but you can customize it to do whatever you want.

The mutation operator defines the procedure for mutating each genome. Mutation means different things for different data types. For example, a typical mutator for a binary string genome flips the bits in the string with a given probability. A typical mutator for a tree, on the other hand, would swap subtrees with a given probability. In general, you should define a mutation that can do both exploration and exploitation; mutation should be able to introduce new genetic material as well as modify existing material. You may want to define multiple types of mutation for a single problem.

The crossover operator defines the procedure for generating a child from two parent genomes. Like the mutation operator, crossover is specific to the data type. Unlike mutation, however, crossover involves multiple genomes. In GAlib, each genome 'knows' its preferred method of mating (the default crossover method) but it is incapable of performing crossover itself. Each genetic algorithm 'knows' how to get the default crossover method from its genomes then use that method to peform the mating. With this model it is possible to derive new genetic algorithm classes that use mating methods other than the defaults defined for a genome.

Each of these methods can be customized so that it is specific not only to the data type, but also to the problem type. This is one way you can put some problem-specific 'intelligence' into the genetic algorithm (I won't go into a discussion about whether or not this is a good thing to do...)

In addition to the three primary operators, each genome must also contain an objective function and may also contain a comparator. The objective function is used to evaluate the genome. The comparator (often referred to as a 'distance function') is used to determine how different one genome is from another. Every genetic algorithm requires that an objective function is defined - this is how the genetic algorithm determines which individuals are better than others. Some genetic algorithms require a comparator.

The library has some basic data types built in, but if you already have an array or list object, for example, then you can quickly build a genome from it by multiply inheriting from your object and the genome object. You can then use this new object directly in the GAlib genetic algorithm objects.

In general, a genetic algorithm does not need to know about the contents of the data structures on which it is operating. The library reflects this generality. You can mix and match genome types with genetic algorithms. The genetic algorithm knows how to clone genomes in order to create populations, initialize genomes to start a run, cross genomes to generate children, and mutate genomes. All of these operations are performed via the genome member functions.

The Population Object

The population object is a container for genomes. Each population object has its own initializer (the default simply calls the initializer for each individual in the population) and evaluator (the default simply calls the evaluator for each individual in the population). It also keeps track of the best, average, deviation, etc for the population. Diversity can be recorded as well, but since diversity calculations often require a great deal of additional compuation, the default is to not record diversity.

The selection method is also defined in the population object. This method is used by the genetic algorithms to choose which individuals should mate.

Each population object has a scaling scheme object associated with it. The scaling scheme object converts the objective score of each genome to a fitness score that the genetic algorithm uses for selection. It also caches fitness information for use later on by the selection schemes.

Objective Functions and Fitness Scaling

Genetic algorithms are often more attractive than gradient search methods because they do not require compilicated differential equations or a smooth search space. The genetic algorithm needs only a single measure of how good a single individual is compared to the other individuals. The objective function provides this measure; given a single solution to a problem, how good is it?

It is important to note the distinction between fitness and objective scores. The objective score is the value returned by your objective function; it is the raw performance evaluation of a genome. The fitness score, on the other hand, is a possibly-transformed rating used by the genetic algorithm to determine the fitness of individuals for mating. The fitness score is typically obtained by a linear scaling of the raw objective scores (but you can define any mapping you want, or no transformation at all). For example, if you use linear scaling then the fitness scores are derived from the objective scores using the fitness proportional scaling technique described in Goldberg's book. The genetic algorithm uses the fitness scores, not the objective scores, to do selection.

You can evaluate the individuals in a population using an individual-based evaluation function (which you define), or a population-based evaluator (also which you define). If you use an individual-based objective, then the function is assigned to each genome. A population-based objective function can make use of individual objective functions, or it can set the individual scores itself.




So what does it look like in C++?

A typical optimization program has the following form:
float Objective(GAGenome&);

main(){
  GA2DBinaryStringGenome genome(width, height, Objective);     // create a genome
  GASimpleGA ga(genome);                            // create the GA
  ga.evolve();                                      // evolve the GA
  cout << ga.statistics() << endl;                   // print out the results
}

float Objective(GAGenome&) {
  // your objective function goes here
}
You can very easily change the behaviour of the genetic algorithm by setting various parameters. Some of the more common ones are set like this:
  ga.populationSize(popsize);
  ga.nGenerations(ngen);
  ga.pMutation(pmut);
  ga.pCrossover(pcross);

  GASigmaTruncationScaling sigmaTruncation;
  ga.scaling(sigmaTruncation);
Alternatively you can have GAlib read the genetic algorithm options from a file or from the command line. This snippet creates a genetic algorithm, reads the parameters from a file, reads parameters (if any) from the command line, performs the evolution, then prints out the statistics from the run.
GASteadyStateGA ga(genome); ga.parameters("settings.txt"); ga.parameters(argc, argv); ga.evolve(); cout << ga.statistics() << endl;
A typical (albeit simple) objective function looks like this (this one gives a higher score to a binary string genome that contains all 1s):
float
Objective(GAGenome & g)
{
  GA1DBinaryStringGenome & genome = (GA1DBinaryStringGenome &)g;
  float score=0.0;
  for(int i=0; i<genome.length(); i++)
    score += genome.gene(i);
  return score;
}
You can define the objective function as a static member of a derived class, or just define a function and use it with the existing GAlib genome classes.

When you write an objective function, you must first cast the generic genome into the type of genome that your objective function is expecting. From that point on you can work with the specific genome type. Each objective function returns a single value that represents the objective score of the genome that was passed to the objective function.

Please see the examples for more samples of the library in action. And see the programming interface page for a complete list of member functions and built-in operators.




What can the operators do?

Here are some examples of the types of mutation and crossover that can be done using GAlib. Traditional crossover generates two children from two parents, and mutation is typically applied to a single individual. However, many other types of crossover and mutation are possible, such as crossover using three or more parents, asexual crossover or population-based mutation. The following examples illustrate some of the standard, sexual crossover and individual mutation methods in GAlib.

tree_single_point
Tree Single Point Crossover
tree_swap_mutate
Sub-Tree Swap Mutation
tree_swap_node
Tree Node Swap Mutation


tree_destructive
Sub-Tree Destructive Mutation
list_single_point
List Single Point Crossover
list_order
List Order-Based Crossover
list_generative
List Generative Mutation
list_destructive
List Destructive Mutation
list_swap_node
List Swap Node Mutation
list_swap_sequence
List Swap Sequence Mutation
array_single_point
Fixed-Length Array Single Point Crossover
array_single_point
Variable-Length Array Single Point Crossover
array_uniform
Array Uniform Crossover



How do I define my own operators?


Defining the operators is only as difficult as figuring out the algorithm you want to implement. As far as the actual implementation goes, there's not much to it. To assign an operator to a genome, just use the appropriate member function. For example, the following code snippet assigns 'MyInitializer' as the initialization function and 'MyCrossover' as the crossover function for a binary string genome.
  GA1DBinaryStringGenome genome(20);
  genome.initializer(MyInitializer);
  genome.crossover(MyCrossover);
If you do this to the first genome (the one you use to create the genetic algorithm) then all of the ones that the GA clones will have the same operators defined for them.

When you derive your own genome class you will typically hard-code the operators into the genome like this:

  class MyGenome : public GAGenome {
  public:
    static void RandomInitializer(GAGenome&);
    static int JuggleCrossover(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*);
    static int KillerMutate(GAGenome&, float);
    static float ElementComparator(const GAGenome&, const GAGenome&);
    static float ThresholdObjective(GAGenome&);
  public:
    MyGenome() {
      initializer(RandomInitializer);
      crossover(JuggleCrossover);
      mutator(KillerMutate);
      comparator(ElementComparator);
      evaluator(ThresholdObjective);
    }

    // remainder of class definition here

  };
Notice how easy it becomes to change operators. You can very easily define a multitude of operators for a single representation and experiment with them to see which performs better.

Why are the genome operators GAlib not member functions? The primary reason is so that you do not have to derive a new class in order to change the behaviour of one of the built-in genome types. In addition, the use of function pointers rather than member functions lets us change operators at run-time (unlike member functions or templatized classes). And they are faster than virtual functions (OK, so this the virtual/non-virtual component is a pretty small fraction of actual execution time compared to most objective functions...). On the down side, they permit you to make some ugly mistakes by improperly casting.



The definition for the List1PtCrossover looks like this:
This crossover picks a single point in the parents then generates one or two children from the two halves of each parent.
template <class T> int
OnePointCrossover(const GAGenome& p1, const GAGenome& p2, GAGenome* c1, GAGenome* c2){
  GAListGenome<T> &mom=(GAListGenome<T> &)p1;
  GAListGenome<T> &dad=(GAListGenome<T> &)p2;

  int nc=0;
  unsigned int a = GARandomInt(0, mom.size());
  unsigned int b = GARandomInt(0, dad.size());
  GAList<T> * list;

// first do the sister...

  if(c1){
    GAListGenome<T> &sis=(GAListGenome<T> &)*c1;
    sis.GAList<T>::copy(mom);
    list = dad.GAList<T>::clone(b);
    if(a < mom.size()){
      T *site = sis.warp(a);
      while(sis.tail() != site)
        sis.destroy();          // delete the tail node
      sis.destroy();            // trash the trailing node (list[a])
    }
    else{
      sis.tail();               // move to the end of the list
    }
    sis.insert(list);           // stick the clone onto the end
    delete list;
    sis.warp(0);                // set iterator to head of list

    nc += 1;
  }

// ...now do the brother

  if(c2){
    GAListGenome<T> &bro=(GAListGenome<T> &)*c2;
    bro.GAList<T>::copy(dad);
    list = mom.GAList<T>::clone(a);
    if(b < dad.size()){
      T *site = bro.warp(b);
      while(bro.tail() != site)
        bro.destroy();          // delete the tail node
      bro.destroy();            // trash the trailing node (list[a])
    }
    else{
      bro.tail();               // move to the end of the list
    }
    bro.insert(list);           // stick the clone onto the end
    delete list;
    bro.warp(0);                // set iterator to head of list

    nc += 1;
  }

  return nc;
}


The definition for FlipMutator for 1DArrayAlleles looks like this:
This mutator flips the value of a single element of the array to any of the possible allele values.
int 
FlipMutator(GAGenome & c, float pmut)
{
  GA1DArrayAlleleGenome<ARRAY_TYPE> &child=(GA1DArrayAlleleGenome<ARRAY_TYPE> &)c;
  register int n, i;
  if(pmut <= 0.0) return(0);

  float nMut = pmut * (float)(child.length());
  if(nMut < 1.0){		// we have to do a flip test on each bit
    nMut = 0;
    for(i=child.length()-1; i>=0; i--){
      if(GAFlipCoin(pmut)){
	child.gene(i, child.alleleset().allele());
	nMut++;
      }
    }
  }
  else{				// only flip the number of bits we need to flip
    for(n=0; n<nMut; n++){
      i = GARandomInt(0, child.length()-1); // the index of the bit to flip
      child.gene(i, child.alleleset().allele());
    }
  }
  return((int)nMut);
}


And the definition for a typical initializer looks like this:
This initializer creates a tree of bounded random size and forkiness.
void
TreeInitializer(GAGenome & c)
{
  GATreeGenome<Point> &tree=(GATreeGenome<Point> &)c;

  tree.root();
  tree.destroy();   // destroy any pre-existing tree

  Point p(0,0,0);
  tree.insert(p,GATreeBASE::ROOT);
  int n = GARandomInt(0,MAX_CHILDREN);	// limit number of children
  for(int i=0; i<n; i++)
    DoChild(tree, 0);
}

void
DoChild(GATreeGenome<Point> & tree, int depth)
{
  if(depth >= MAX_DEPTH) return;     // limit depth of the tree
  int n = GARandomInt(0,MAX_CHILDREN);	// limit number of children

  Point p(GARandomFloat(0,25),GARandomFloat(0,25),GARandomFloat(0,25));
  tree.insert(p,GATreeBASE::BELOW);

  for(int i=0; i<n; i++)
    DoChild(tree, depth+1);

  tree.parent();		// move the iterator up one level
}


What about deriving my own genome class?

Here is the definition of a genome that contains an arbitrary number of lists. It could easily be modified to become a diploid genome. It is used in exactly the same way that the built-in genomes are used. For a simpler example, see the GNU example which integrates the GNU BitString object with GAlib to form a new genome class.
class RobotPathGenome : public GAGenome {
public:
  GADefineIdentity("RobotPathGenome", 251);
  static void Initializer(GAGenome&);
  static int Mutator(GAGenome&, float);
  static float Comparator(const GAGenome&, const GAGenome&);
  static float Evaluator(GAGenome&);
  static void PathInitializer(GAGenome&);
public:
  RobotPathGenome(int nrobots, int pathlength);
  RobotPathGenome(const RobotPathGenome & orig);
  RobotPathGenome& operator=(const GAGenome & arg);
  virtual ~RobotPathGenome();
  virtual GAGenome *clone(GAGenome::CloneMethod) const ;
  virtual void copy(const GAGenome & c);
  virtual int equal(const GAGenome& g) const ;
  virtual int read(istream & is);
  virtual int write(ostream & os) const ;

  GAListGenome<int> & path(int i){ return *list[i]; }
  int npaths() const { return n; }
  int length() const { return l; }

protected:
  int n, l;
  GAListGenome<int> **list;
};
Please see the examples for complete details.
Matthew Wall, 23 March 1996 galib247/doc/References.html0100644003643600364360000000413710573535471015161 0ustar mwallmwallGAlib: References Some genetic algorithm references...

These are some of the more common references for those interested in genetic algorithms and genetic algorithms implementations.
Evolutionary Algorithms in Theory and Practice
T. Baeck, Oxford, NY, 1996

Handbook of Genetic Algorithms
Lawrence Davis (editor), Van Nostrand Reinholt, NY, 1991

Evolutionary Computation
D.B. Fogel, IEEE Press, NY, 1995

Genetic Algorithms in Search and Optimization
David Edward Goldberg, Addison-Wesley Pub. Co., 1989
ISBN 0-201-15767-5

Adaptation in Natural and Artificial Systems, 2nd. Edition
J.H. Holland, MIT Press, Cambridge, MA, 1992

Genetic Programming
J. Koza, MIT Press, Cambridge, MA, 1992

Genetic Algorithms + Data Structures = Evolution Programs
Zbginew Michalewicz, Springer, Berlin, 1994

An Introduction to Genetic Algorithms
Melanie Mitchell, MIT Press, Cambridge, MA, 1996

Evolution and Optimum Seeking
H.-P. Schwefel, Wiley, NY, 1994

Numerical Recipes in C: The Art of Scientific Computing
Cambridge University Press, (c) 1988-1992
ISBN 0-521-43108-5

Matthew Wall, 20 March 1996 galib247/examples/0040755003643600364360000000000010573535777013272 5ustar mwallmwallgalib247/examples/ChangeLog0100644003643600364360000000143610573535500015025 0ustar mwallmwall2005-01-11 Matthew Wall * graphic/gaview.C: keep gcc3 happy. 2005-01-06 Matthew Wall * randtest.C: accommodate some strangeness from ms vcpp 7 2004-12-28 Matthew Wall * makefile.win32: added time stamps (sort of) and for loop. windows scripting *really* sucks. * makefile: do not assume that . is in the path * ex8.C: adhere to c++ standard * ex11.C: adhere to c++ standard * ex14.C: adhere to c++ standard * ex16.C: adhere to c++ standard * ex17.C: adhere to c++ standard * ex26.C: adhere to c++ standard * ex6.C: adhere to c++ standard 2004-12-28 Matthew Wall * ex15.C: avoid unsigned int comparison warning * ex13.C: avoid unsigned in comparison warning galib247/examples/ex1.C0100644003643600364360000000661310573535500014056 0ustar mwallmwall/* ---------------------------------------------------------------------------- ex1.C mbwall 28jul94 Copyright (c) 1995-1996 Massachusetts Institute of Technology DESCRIPTION: Example program for the SimpleGA class and 2DBinaryStringGenome class. This program tries to fill the 2Dgenome with alternating 1s and 0s. This example uses the default crossover (single point), default mutator (uniform random bit flip), and default initializer (uniform random) for the 2D genome. Notice that one-point crossover is not necessarily the best kind of crossover to use if you want to generate a 'good' genome with this kind of objective function. But it does work. ---------------------------------------------------------------------------- */ #include // we're going to use the simple GA #include // and the 2D binary string genome #include #define cout STD_COUT float Objective(GAGenome &); // This is the declaration of our obj function. // The definition comes later in the file. int main(int argc, char **argv) { cout << "Example 1\n\n"; cout << "This program tries to fill a 2DBinaryStringGenome with\n"; cout << "alternating 1s and 0s using a SimpleGA\n\n"; cout.flush(); // See if we've been given a seed to use (for testing purposes). When you // specify a random seed, the evolution will be exactly the same each time // you use that seed number. for(int ii=1; ii #include #include #include #include #define cout STD_COUT #define cerr STD_CERR #define endl STD_ENDL #define ofstream STD_OFSTREAM #define USE_RAW_SINE #ifndef M_PI #define M_PI 3.14159265358979323846 #endif #define NBITS 8 #ifdef USE_RAW_SINE #define FUNCTION Function1 #define MIN_VALUE 0 #define MAX_VALUE 5 #else #define FUNCTION Function2 #define MIN_VALUE -100 #define MAX_VALUE 100 #endif float Function1(float); float Function2(float); float Objective(GAGenome &); float BitDistance(const GAGenome & a, const GAGenome & b); float PhenotypeDistance(const GAGenome & a, const GAGenome & b); int main(int argc, char **argv) { cout << "Example 10\n\n"; cout << "This program uses sharing to do speciation. The objective\n"; cout << "function has more than one optimum, so different genomes\n"; cout << "may have equally high scores. Speciation keeps the population\n"; cout << "from clustering at one optimum.\n"; cout << " Both gene-wise and phenotype-wise distance functions are used.\n"; cout << " Populations from all three runs are written to the files \n"; cout << "pop.nospec.dat, pop.genespec.dat and pop.phenespec.dat. The\n"; cout << "function is written to the file sinusoid.dat\n\n"; cout.flush(); // See if we've been given a seed to use (for testing purposes). When you // specify a random seed, the evolution will be exactly the same each time // you use that seed number. for(int ii=1; ii 100) y = 0; if(y < 0) y = 0; return y+0.00001; } // Here are a couple of possible distance functions for this problem. One of // them uses the genes to determine the same-ness, the other uses the // phenotypes to determine same-ness. If the genomes are the same, then // we return a 0. If they are completely different then we return a 1. // In either case, you should be sure that the distance function will return // values only between 0 and 1 inclusive. If your function returns values // outside these limits, the GA will produce bogus results and it WILL NOT warn // you that your distance function is brain-dead! // This distance function uses the genes to determine same-ness. All we do // is check to see if the bit strings are identical. float BitDistance(const GAGenome & c1, const GAGenome & c2){ GABin2DecGenome & a = (GABin2DecGenome &)c1; GABin2DecGenome & b = (GABin2DecGenome &)c2; float x=0; for(int i=a.length()-1; i>=0; i--) x += (a[i] != b[i] ? 1 : 0); return x/a.length(); } // This distance function looks at the phenotypes rather than the genes of the // genome. This distance function will try to drive them to extremes. float PhenotypeDistance(const GAGenome & c1, const GAGenome & c2){ GABin2DecGenome & a = (GABin2DecGenome &)c1; GABin2DecGenome & b = (GABin2DecGenome &)c2; return fabs(a.phenotype(0) - b.phenotype(0)) / (MAX_VALUE-MIN_VALUE); } galib247/examples/ex11.C0100644003643600364360000001355310573535500014140 0ustar mwallmwall/* ---------------------------------------------------------------------------- ex11.C mbwall 13apr95 Copyright (c) 1995-1996 Massachusetts Institute of Technology DESCRIPTION: This example shows how to use an order-based list genome. ---------------------------------------------------------------------------- */ #include #include #include #include #define cout STD_COUT #define ostream STD_OSTREAM // The objective function tells how good a genome is. The Initializer defines // how the lists should be initialized. float objective(GAGenome &); void ListInitializer(GAGenome &); int main(int argc, char *argv[]) { cout << "Example 11\n\n"; cout << "This program illustrates the use of order-based lists. The\n"; cout << "list in this problem contains 25 numbers, 0 to 24. It tries\n"; cout << "to put them in descending order from 24 to 0.\n\n"; cout.flush(); // See if we've been given a seed to use (for testing purposes). When you // specify a random seed, the evolution will be exactly the same each time // you use that seed number. for(int ii=1; ii genome(objective); genome.initializer(ListInitializer); genome.mutator(GAListGenome::SwapMutator); // Now that we have our genome, we create the GA (it clones the genome to // make all of the individuals for its populations). Set the parameters on // the GA then let it evolve. GASteadyStateGA ga(genome); ga.crossover(GAListGenome::PartialMatchCrossover); ga.parameters(params); ga.evolve(); // Assign the best that the GA found to our genome then print out the results. genome = ga.statistics().bestIndividual(); cout << "the ga generated the following list (objective score is "; cout << genome.score() << "):\n" << genome << "\n"; cout << "best of generation data are in '" << ga.scoreFilename() << "'\n"; cout << ga.parameters() << "\n"; // char *fn; // ga.get(gaNscoreFilename, &fn); // cout << "filename is '" << fn << "'\n"; return 0; } /* ---------------------------------------------------------------------------- Objective function The objective function gives one point for every number in the correct position. We're trying to get a sequence of numbers from n to 0 in descending order. ---------------------------------------------------------------------------- */ float objective(GAGenome & c) { GAListGenome & genome = (GAListGenome &)c; float score = (*genome.head() == genome.size()-1); // move to head of list for(int i=genome.size()-2; i>0; i--) score += (*genome.next() == i); // cycle through list and look at nodes return score; } /* ---------------------------------------------------------------------------- List Genome Operators ------------------------------------------------------------------------------- The initializer creates a list with n elements in it and puts a unique digit in each one. After we make the list, we scramble everything up. ---------------------------------------------------------------------------- */ void ListInitializer(GAGenome & c) { GAListGenome &child=(GAListGenome &)c; while(child.head()) child.destroy(); // destroy any pre-existing list int n=25; child.insert(0,GAListBASE::HEAD); // the head node contains a '0' for(int i=1; i int GAListGenome::write(ostream & os) const { int *cur, *head; GAListIter tmpiter(*this); if((head=tmpiter.head()) != 0) os << *head << " "; for(cur=tmpiter.next(); cur && cur != head; cur=tmpiter.next()) os << *cur << " "; return os.fail() ? 1 : 0; } // force instantiations for compilers that do not do auto instantiation // for some compilers (e.g. metrowerks) this must come after any // specializations or you will get 'multiply-defined errors when you compile. #if !defined(GALIB_USE_AUTO_INST) #include #include GALIB_INSTANTIATION_PREFIX GAList; GALIB_INSTANTIATION_PREFIX GAListGenome; #endif galib247/examples/ex12.C0100644003643600364360000000726510573535500014144 0ustar mwallmwall/* ---------------------------------------------------------------------------- ex12.C mbwall 13apr95 Copyright (c) 1995-1996 Massachusetts Institute of Technology DESCRIPTION: This example shows how to use an order-based string genome. ---------------------------------------------------------------------------- */ #include #include #include #include #define cout STD_COUT #define INSTANTIATE_STRING_GENOME #include // This is the declaration of the objective function that we will use in this // example. float objective(GAGenome &); // Every genome must have an initializer. Here we declare our own initializer // that will be used in this example. void AlphabetInitializer(GAGenome &); int main(int argc, char *argv[]) { cout << "Example 12\n\n"; cout << "This program illustrates the use of order-based strings. The\n"; cout << "string in this problem contains 26 letters, a to z. It tries\n"; cout << "to put them in alphabetic order.\n\n"; cout.flush(); // See if we've been given a seed to use (for testing purposes). When you // specify a random seed, the evolution will be exactly the same each time // you use that seed number. for(int ii=1; ii #include #include #include #include #define cout STD_COUT #define cerr STD_CERR #define ifstream STD_IFSTREAM typedef struct _UserData { int width, height; short **picture_target; float *numbers_target; GA2DBinaryStringGenome *picture_genome; GABin2DecGenome *numbers_genome; } UserData; float PictureObjective(GAGenome &); float NumbersObjective(GAGenome &); int main(int argc, char *argv[]) { cout << "Example 13\n\n"; cout << "This program runs a GA-within-GA. The outer level GA tries to\n"; cout << "match the pattern read in from a file. The inner level GA is\n"; cout << "run only when the outer GA reaches a threshhold objective score\n"; cout << "then it tries to match a sequence of numbers that were generated\n"; cout << "randomly at the beginning of the program's execution.\n\n"; cout << "You might have to run the primary GA for more than 5000\n"; cout << "generations to get a score high enough to kick in the secondary\n"; cout << "genetic algorithm. Use the ngen option to do this on the\n"; cout << "command line.\n\n"; // See if we've been given a seed to use (for testing purposes). When you // specify a random seed, the evolution will be exactly the same each time // you use that seed number. unsigned int seed = 0; for(int ii=1; ii> data.height >> data.width; data.picture_target = new short*[data.width]; for(i=0; i> data.picture_target[i][j]; inStream.close(); // Print out the pattern to be sure we got the right one. cout << "input pattern:\n"; for(j=0; jpicture_target[i][j]); float correct = value / ((float)genome.width() * (float)genome.height()); // if we get at least 95% of the pixels right, then run the secondary ga. if(correct > 0.95) { GABin2DecGenome& num_genome = (GABin2DecGenome&)(*data->numbers_genome); GAIncrementalGA ga(num_genome); ga.populationSize(550); ga.nGenerations(50); ga.pMutation(0.01); ga.pCrossover(0.9); ga.evolve(); *data->numbers_genome = ga.statistics().bestIndividual(); correct += data->numbers_genome->score(); } return correct; } // This is the objective function for matching the sequence of numbers. float NumbersObjective(GAGenome & c) { GABin2DecGenome & genome = (GABin2DecGenome &)c; UserData * data = (UserData *)c.userData(); float value=genome.nPhenotypes(); for(int i=0; inumbers_target[i])); value /= genome.nPhenotypes(); return value; } galib247/examples/ex14.C0100644003643600364360000002625110573535500014142 0ustar mwallmwall/* ---------------------------------------------------------------------------- ex14.C mbwall 29apr95 Copyright (c) 1995-1996 Massachusetts Institute of Technology DESCRIPTION: Example program for a composite genome derived from the GAGenome and containing a list of lists. This example shows how to derive your own genome class and illustrates the use of one of the template genomes (GAListGenome) from the GAlib. ---------------------------------------------------------------------------- */ #include #include #include #include #define cout STD_COUT #define cerr STD_CERR #define endl STD_ENDL #define istream STD_ISTREAM #define ostream STD_OSTREAM // Here we specify how big the lists will be and how many lists will be in each // composite genome. These are the default values - you can change them from // the command line. Beware that this program will break if nrobots is bigger // than the size of the lists. int listsize = 10; int nrobots = 6; // This is the class definition. We override the methods of the base class and // define a few methods of our own to access the protected members. The list // genomes in the composite genome are assigned the 'List' operators // by default (they can be overridden by using the 'Operator' members on the // lists explicitly). // The ID can be any number over 200 (IDs under 200 are reserved for use by // GAlib objects). class RobotPathGenome : public GAGenome { public: GADefineIdentity("RobotPathGenome", 251); static void Initializer(GAGenome&); static int Mutator(GAGenome&, float); static float Comparator(const GAGenome&, const GAGenome&); static float Evaluator(GAGenome&); static void PathInitializer(GAGenome&); static int Crossover(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*); public: RobotPathGenome(int nrobots, int pathlength); RobotPathGenome(const RobotPathGenome & orig) { n=l=0; list=0; copy(orig); } RobotPathGenome operator=(const GAGenome & arg) { copy(arg); return *this; } virtual ~RobotPathGenome(); virtual GAGenome *clone(GAGenome::CloneMethod) const ; virtual void copy(const GAGenome & c); virtual int equal(const GAGenome& g) const; virtual int read(istream & is); virtual int write(ostream & os) const ; GAListGenome & path(const int i){return *list[i];} int npaths() const { return n; } int length() const { return l; } protected: int n, l; GAListGenome **list; }; RobotPathGenome::RobotPathGenome(int nrobots, int pathlength) : GAGenome(Initializer, Mutator, Comparator){ evaluator(Evaluator); crossover(Crossover); n = nrobots; l = pathlength; list = (n ? new GAListGenome * [n] : (GAListGenome **)0); for(int i=0; i; list[i]->initializer(PathInitializer); list[i]->mutator(GAListGenome::SwapMutator); } } void RobotPathGenome::copy(const GAGenome& g) { if(&g != this && sameClass(g)){ GAGenome::copy(g); // copy the base class part RobotPathGenome & genome = (RobotPathGenome &)g; if(n == genome.n){ for(int i=0; icopy(*genome.list[i]); } else{ int i; for(i=0; i * [n]; for(i=0; i *)genome.list[i]->clone(); } } } RobotPathGenome::~RobotPathGenome(){ for(int i=0; iequal(*genome.list[i]); return flag; } int RobotPathGenome::read(istream & is) { for(int i=0; i> *(list[i]); return is.fail() ? 1 : 0; } int RobotPathGenome::write(ostream & os) const { for(int i=0; i::PartialMatchCrossover(mom.path(i), dad.path(i), &sis.path(i), &bro.path(i)); sis._evaluated = gaFalse; bro._evaluated = gaFalse; n=2; } else if(c) { RobotPathGenome& sis = (RobotPathGenome &)*c; for(int i=0; i::PartialMatchCrossover(mom.path(i), dad.path(i), &sis.path(i), 0); sis._evaluated = gaFalse; n=1; } else if(d) { RobotPathGenome& bro = (RobotPathGenome &)*d; for(int i=0; i::PartialMatchCrossover(mom.path(i), dad.path(i), 0, &bro.path(i)); bro._evaluated = gaFalse; n=1; } return n; } // This is the initialization operator for our lists. We create a list that is // n long and whose nodes contain numbers in sequence. // The first thing to do in the initializer is to clear out any old // contents - we do not want to build our new list on a previously existing // one! Notice that we have to cast the genome into the type of // genome we're using (in this case a list). The GA always operates on // generic genomes. // All of our lists must be the same length since we're going to use the // ordered crossover operators. void RobotPathGenome::PathInitializer(GAGenome & c){ GAListGenome & list = (GAListGenome &)c; // We must first destroy any pre-existing list. while(list.head()) list.destroy(); // Insert the head of the list. This node has a random number in it, but the // number is in a range different than those in the rest of the list. This // way we'll be able to see how the lists get scrambled up. Since we're using // ordered crossover (see the header file) we should never end up with more // than one node in each list that has a given value. list.insert(0, GAListBASE::HEAD); // Loop through n times and append nodes onto the end of the list. int i; for(i=0; i int GAListGenome::write(ostream & os) const { int *cur, *head; GAListIter iter(*this); if((head=iter.head()) != 0) os << *head << " "; for(cur=iter.next(); cur && cur != head; cur=iter.next()) os << *cur << " "; return os.fail() ? 1 : 0; } int main(int argc, char *argv[]) { cout << "Example 14\n\n"; cout << "This example shows how to create a genome that contains\n"; cout << "a list of lists. We create a composite genome that has\n"; cout << "lists in it. Each list has some nodes, only one of which\n"; cout << "contains the number 0. The objective is to move the node with\n"; cout << "number 0 in it to the nth position where n is the number of the\n"; cout << "list within the composite genome.\n\n"; cout.flush(); // See if we've been given a seed to use (for testing purposes). When you // specify a random seed, the evolution will be exactly the same each time // you use that seed number. int i; for(i=1; i= argc){ cerr << argv[0] << ": number of robots needs a value.\n"; exit(1); } else{ nrobots = atoi(argv[i]); continue; } } else if(strcmp("pl", argv[i]) == 0){ if(++i >= argc){ cerr << argv[0] << ": path length needs a value.\n"; exit(1); } else{ listsize = atoi(argv[i]); continue; } } else if(strcmp(argv[i],"seed") == 0) { if(++i >= argc){ cerr << argv[0] << ": seed needs a value.\n"; exit(1); } else { GARandomSeed((unsigned int)atoi(argv[i])); } } else if(strcmp("help",argv[i]) == 0){ cerr << "valid arguements include standard GAlib arguments plus:\n"; cerr << " nr\tnumber of robots (" << nrobots << ")\n"; cerr << " pl\tlength of the paths (" << listsize << ")\n"; cerr << "\n"; exit(1); } } if(listsize < nrobots) { cerr << "path length must be greater than the number of robots.\n"; exit(1); } RobotPathGenome genome(nrobots, listsize); GASteadyStateGA ga(genome); ga.parameters(argc,argv); ga.evolve(); genome.initialize(); cout << "a randomly-generated set of paths:\n" << genome << endl; cout << "the ga generated:\n" << ga.statistics().bestIndividual() << "\n"; return 0; } // force instantiations for compilers that do not do auto instantiation. // for some compilers (e.g. metrowerks) this must come after any // specializations or you will get 'multiply-defined errors when you compile. #if !defined(GALIB_USE_AUTO_INST) #include #include GALIB_INSTANTIATION_PREFIX GAList; GALIB_INSTANTIATION_PREFIX GAListGenome; #endif galib247/examples/ex15.C0100644003643600364360000001171710573535500014144 0ustar mwallmwall/* ---------------------------------------------------------------------------- ex15.C mbwall 28jul94 Copyright (c) 1995-1996 Massachusetts Institute of Technology DESCRIPTION: This example nearly identical to example 2, but it uses convergence as the stopping criterion for the GA rather than number-of-generations. ---------------------------------------------------------------------------- */ #include #include #include #include #define cout STD_COUT float objective(GAGenome &); int main(int argc, char **argv) { cout << "Example 15\n\n"; cout << "This program generates a sequence of random numbers then uses\n"; cout << "a simple GA and binary-to-decimal genome to match the\n"; cout << "sequence. It uses the convergence of the best-of-generation\n"; cout << "as the criterion for when to stop.\n\n"; // See if we've been given a seed to use (for testing purposes). When you // specify a random seed, the evolution will be exactly the same each time // you use that seed number. unsigned int seed = 0; for(int ii=1; ii #include #include #include #define cout STD_COUT #define ostream STD_OSTREAM // This is the object that we're going to put in the nodes. Each point has // three coordinates: x,y,z. class Point { public: Point(float x, float y, float z) { _x = x; _y = y; _z = z; } Point(const Point & p) { _x = p._x; _y = p._y; _z = p._z; } Point & operator=(const Point & p) { _x=p._x;_y=p._y;_z=p._z; return *this; } ~Point() {} float x() const { return _x; } float y() const { return _y; } float z() const { return _z; } float x(float val) { return _x=val; } float y(float val) { return _y=val; } float z(float val) { return _z=val; } friend ostream & operator<<(ostream & os, const Point & p){ os << "(" << p._x << ", " << p._y << ", " << p._z << ")"; return os; } protected: float _x, _y, _z; }; // These are the declarations for the functions defined in this file. The // objective function is pretty standard. The tree initializer generates a // random tree. WriteNode is used in the write method for the tree - we // override (specialize) the write method to print out the contents of the // nodes rather than pointers to the contents. float objective(GAGenome &); void TreeInitializer(GAGenome &); void WriteNode(ostream & os, GANode * n); int main(int argc, char **argv) { cout << "Example 16\n\n"; cout << "This example uses a SteadyState GA and Tree genome. It\n"; cout << "tries to maximize the size of the tree genomes that it\n"; cout << "contains. The genomes contain points in its nodes. Two\n"; cout << "different runs are made: first with the swap subtree mutator,\n"; cout << "second with the destructive mutator.\n\n"; cout.flush(); // See if we've been given a seed to use (for testing purposes). When you // specify a random seed, the evolution will be exactly the same each time // you use that seed number. unsigned int seed = 0; for(int ii=1; ii genome(objective); genome.initializer(TreeInitializer); genome.crossover(GATreeGenome::OnePointCrossover); genome.mutator(GATreeGenome::SwapSubtreeMutator); GAPopulation swappop(genome, 50); genome.mutator(GATreeGenome::DestructiveMutator); GAPopulation destpop(genome, 50); GASteadyStateGA ga(genome); ga.nGenerations(10); // first do evolution with subtree swap mutator. ga.population(swappop); cout << "initializing..."; ga.initialize(seed); cout << "evolving for " << ga.nGenerations() << " generations..."; while(!ga.done()){ ga.step(); cout << "."; cout.flush(); } cout << "\n"; genome = ga.statistics().bestIndividual(); cout << "the ga generated a tree with " << genome.size(); cout << " nodes, " << genome.depth() << " levels deep.\n"; // now do evolution with destructive swap mutator ga.population(destpop); cout << "\ninitializing..."; ga.initialize(); cout << "evolving for " << ga.nGenerations() << " generations..."; while(!ga.done()){ ga.step(); cout << "."; cout.flush(); } cout << "\n"; genome = ga.statistics().bestIndividual(); cout << "the ga generated a tree with " << genome.size(); cout << " nodes, " << genome.depth() << " levels deep.\n"; return 0; } /* ---------------------------------------------------------------------------- All we do in this objective function is try to maximize the size of the tree. Just return the tree size. This means that if you run this objective function for many generations you'll run out of memory! There is no limit to tree or list sizes built-in to the GA library. ---------------------------------------------------------------------------- */ float objective(GAGenome & c) { GATreeGenome & chrom = (GATreeGenome &)c; return chrom.size(); } /* ---------------------------------------------------------------------------- This initializer creates a tree of random size (within limits). The maximum number of children any node can have is limited, so is the maximum depth of the tree. We do it recursively. Each point that is inserted into the tree has random contents. The initializer must first destroy any pre-existing tree or else we have a memory leak (the initializer may be called more than once - for example when you re-run the GA). ---------------------------------------------------------------------------- */ const int MAX_DEPTH = 3; const int MAX_CHILDREN = 2; void DoChild(GATreeGenome & tree, int depth) { if(depth >= MAX_DEPTH) return; int n = GARandomInt(0,MAX_CHILDREN); // maximum of 5 children Point p(GARandomFloat(0,25),GARandomFloat(0,25),GARandomFloat(0,25)); tree.insert(p,GATreeBASE::BELOW); for(int i=0; i &tree=(GATreeGenome &)c; // destroy any pre-existing tree tree.root(); tree.destroy(); // create a root node with coordinates 0,0,0, then do the rest. Point p(0,0,0); tree.insert(p,GATreeBASE::ROOT); int n = GARandomInt(0,MAX_CHILDREN); // maximum of 5 children for(int i=0; i * n) { if(!n) return; GANodeBASE * node = (GANodeBASE *)n; os.width(10); os << ((GANode *)node)->contents << " "; os.width(10); if(node->parent) os << ((GANode *)node->parent)->contents << " "; else os << "." << " "; os.width(10); if(node->child) os << ((GANode *)node->child)->contents << " "; else os << "." << " "; os.width(10); if(node->next) os << ((GANode *)node->next)->contents << " "; else os << "." << " "; os.width(10); if(node->prev) os << ((GANode *)node->prev)->contents << "\n"; else os << ".\n"; WriteNode(os, (GANode *)node->child); for(GANodeBASE * tmp=node->next; tmp && tmp != node; tmp=tmp->next){ os.width(10); os << ((GANode *)tmp)->contents << " "; os.width(10); if(tmp->parent) os << ((GANode *)tmp->parent)->contents << " "; else os << "." << " "; os.width(10); if(tmp->child) os << ((GANode *)tmp->child)->contents << " "; else os << "." << " "; os.width(10); if(tmp->next) os << ((GANode *)tmp->next)->contents << " "; else os << "." << " "; os.width(10); if(tmp->prev) os << ((GANode *)tmp->prev)->contents << "\n"; else os << ".\n"; WriteNode(os, (GANode *)tmp->child); } } template <> int GATreeGenome::write(ostream & os) const { os << " node parent child next prev\n"; WriteNode(os, (GANode *)rt); return os.fail() ? 1 : 0; } // force instantiations for compilers that do not do auto instantiation // for some compilers (e.g. metrowerks) this must come after any // specializations or you will get 'multiply-defined errors when you compile. #if !defined(GALIB_USE_AUTO_INST) #include #include GALIB_INSTANTIATION_PREFIX GATreeGenome; GALIB_INSTANTIATION_PREFIX GATree; #endif galib247/examples/ex17.C0100644003643600364360000000771710573535500014153 0ustar mwallmwall/* ---------------------------------------------------------------------------- ex17.C mbwall 5may95 Copyright (c) 1995-1996 Massachusetts Institute of Technology DESCRIPTION: Example program illustrating the use of a 2DArrayGenome with trinary alleles (-1, 0, 1). The objective function for this program tries to alternate 0 and 1 then put -1 in the corners. ---------------------------------------------------------------------------- */ #include #include #include #include #define cout STD_COUT #define endl STD_ENDL #define ostream STD_OSTREAM float objective(GAGenome &); int main(int argc, char *argv[]) { cout << "Example 17\n\n"; cout << "This program illustrates the use of a 2DArrayGenome with\n"; cout << "three alleles. It tries to fill a 2D array with alternating\n"; cout << "0s and 1s, and -1s at the corners. You will have to run it\n"; cout << "for something like 10000 generations to get the perfect score.\n\n"; cout.flush(); // See if we've been given a seed to use (for testing purposes). When you // specify a random seed, the evolution will be exactly the same each time // you use that seed number. unsigned int seed = 0; for(int ii=1; ii alleles(3, aset); GA2DArrayAlleleGenome genome(20, 20, alleles, objective); genome.initializer(GA2DArrayAlleleGenome::UniformInitializer); genome.mutator(GA2DArrayAlleleGenome::FlipMutator); genome.crossover(GA2DArrayGenome::OnePointCrossover); GASteadyStateGA ga(genome); GASigmaTruncationScaling trunc; ga.scaling(trunc); ga.set(gaNpopulationSize, 40); ga.set(gaNpCrossover, 0.6); ga.set(gaNpMutation, 0.001); ga.set(gaNnGenerations, 10000); ga.set(gaNpReplacement, 0.25); ga.parameters(argc, argv); ga.initialize(seed); cout << "evolving..."; while(!ga.done()){ ga.step(); if(ga.generation() % 50 == 0){ cout << "."; cout.flush(); } } cout << "\n\n"; cout << "the ga generated:\n" << ga.statistics().bestIndividual() << endl; return 0; } float objective(GAGenome & c) { GA2DArrayAlleleGenome & genome = (GA2DArrayAlleleGenome &)c; float value=0.0; int count=0; for(int i=0; i int GA2DArrayAlleleGenome::write(ostream & os) const { for(unsigned int j=0; j #include GALIB_INSTANTIATION_PREFIX GAAlleleSet; GALIB_INSTANTIATION_PREFIX GAAlleleSetCore; GALIB_INSTANTIATION_PREFIX GAArray; GALIB_INSTANTIATION_PREFIX GA2DArrayGenome; GALIB_INSTANTIATION_PREFIX GA2DArrayAlleleGenome; #endif galib247/examples/ex18.C0100644003643600364360000001364210573535500014146 0ustar mwallmwall/* ---------------------------------------------------------------------------- ex18.C mbwall 28jul94 Copyright (c) 1995-1996 Massachusetts Institute of Technology DESCRIPTION: Example program for the SimpleGA class and 2DBinaryStringGenome class. This program reads in a 2D pattern from a data file then tries to match the pattern in a 2D binary string genome. The type of GA can be specified at the command line. ---------------------------------------------------------------------------- */ #include #include #include #include #define cout STD_COUT #define cerr STD_CERR #define ifstream STD_IFSTREAM float objective(GAGenome &); int cntr=0; int main(int argc, char *argv[]) { cout << "Example 18\n\n"; cout << "This program is designed to compare the GA types. You can\n"; cout << "specify steady-state, incremental, or simple GA and tweak any\n"; cout << "of the parameters for each of these GA types. The objective\n"; cout << "function tries to match a pattern read in from a file.\n\n"; cout.flush(); // See if we've been given a seed to use (for testing purposes). When you // specify a random seed, the evolution will be exactly the same each time // you use that seed number. unsigned int seed = 0; for(int ii=1; ii= argc){ cerr << argv[0] << ": which GA do you want? (simple, ss, or inc)\n"; exit(1); } else{ if(strcmp(argv[i],"simple") == 0) whichGA = SIMPLE; else if(strcmp(argv[i],"ss") == 0) whichGA = STEADY_STATE; else if(strcmp(argv[i],"inc") == 0) whichGA = INCREMENTAL; else cerr << argv[0] << ": ga must be one of: simple, ss, or inc.\n"; continue; } } else if(strcmp("file", argv[i]) == 0 || strcmp("f", argv[i]) == 0){ if(++i >= argc){ cerr << argv[0] << ": the file option needs a filename.\n"; exit(1); } else{ sprintf(filename, argv[i]); continue; } } else if(strcmp("seed", argv[i]) == 0){ if(++i < argc) continue; continue; } else { cerr << argv[0] << ": unrecognized arguement: " << argv[i] << "\n\n"; cerr << "valid arguements include standard GAlib arguments plus:\n"; cerr << " f\tfilename from which to read (" << filename << ")\n"; cerr << "\n"; cerr << " ga simple|ss|inc\twhich GA to use (simple)\n"; cerr << "\n"; exit(1); } } // Read in the pattern from the specified file. File format is pretty simple: // two integers that give the height then width of the matrix, then the matrix // of 1's and 0's (with whitespace inbetween). ifstream inStream(filename); if(!inStream){ cerr << "Cannot open " << filename << " for input.\n"; exit(1); } int height, width; inStream >> height >> width; short **target = new short*[width]; for(i=0; i> target[i][j]; inStream.close(); // Print out the pattern to be sure we got the right one. cout << "input pattern:\n"; for(j=0; j #include #include #include #include #define cout STD_COUT #define cerr STD_CERR double Gauss(double mean, double variance); float DeJong1(GAGenome &); float DeJong2(GAGenome &); float DeJong3(GAGenome &); float DeJong4(GAGenome &); float DeJong5(GAGenome &); GAGenome::Evaluator objective[5] = {DeJong1,DeJong2,DeJong3,DeJong4,DeJong5}; int main(int argc, char *argv[]) { cout << "Example 19\n\n"; cout << "This program runs the DeJong test problems.\n\n"; cout.flush(); // See if we've been given a seed to use (for testing purposes). When you // specify a random seed, the evolution will be exactly the same each time // you use that seed number. unsigned int seed = 0; for(int ii=1; ii= argc){ cerr << argv[0] << ": you must specify a function (1-5)\n"; exit(1); } else{ whichFunction = atoi(argv[i]) - 1; if(whichFunction < 0 || whichFunction > 4){ cerr << argv[0] << ": the function must be in the range [1,5]\n"; exit(1); } continue; } } else if(strcmp("seed", argv[i]) == 0){ if(++i < argc) continue; continue; } else { cerr << argv[0] << ": unrecognized arguement: " << argv[i] << "\n\n"; cerr << "valid arguements include standard GAlib arguments plus:\n"; cerr << " f\twhich function to evaluate (all)\n"; cerr << "parameters are:\n\n" << params << "\n\n"; exit(1); } } // Create the phenotype map depending on which dejong function we are going // to be running. GABin2DecPhenotype map; switch(whichFunction){ case 0: map.add(16, -5.12, 5.12); map.add(16, -5.12, 5.12); map.add(16, -5.12, 5.12); break; case 1: map.add(16, -2.048, 2.048); map.add(16, -2.048, 2.048); break; case 2: map.add(16, -5.12, 5.12); map.add(16, -5.12, 5.12); map.add(16, -5.12, 5.12); map.add(16, -5.12, 5.12); map.add(16, -5.12, 5.12); break; case 3: { for(int j=0; j<30; j++) map.add(16, -1.28, 1.28); } break; case 4: map.add(16, -65.536, 65.536); map.add(16, -65.536, 65.536); break; default: map.add(16, 0, 0); break; } // Now create the sample genome and run the GA. GABin2DecGenome genome(map, objective[whichFunction]); // GAStatistics stats; GASteadyStateGA ga(genome); ga.parameters(params); GASigmaTruncationScaling scaling; ga.scaling(scaling); cout << "running DeJong function number " << (whichFunction + 1) << " ...\n"; ga.evolve(seed); cout << "the ga generated:\n" << ga.statistics().bestIndividual() << "\n"; cout << "\nthe statistics for the run are:\n" << ga.statistics(); cout << "\nbest-of-generation data are in 'bog.dat'\n"; cout.flush(); return 0; } // DeJong's first function is: // // f1(x1,x2,x3) = x1*x1 + x2*x2 + x3*x3 // // where each x is in the range [-5.12,5.12] float DeJong1(GAGenome & c) { GABin2DecGenome & genome = (GABin2DecGenome &)c; float value=0; value += genome.phenotype(0) * genome.phenotype(0); value += genome.phenotype(1) * genome.phenotype(1); value += genome.phenotype(2) * genome.phenotype(2); return(value); } // DeJong's second function is: // // f2(x1,x2) = 100 * (x1*x1 - x2)^2 + (1 - x1)^2 // // where each x is in the range [-2.048,2.048] float DeJong2(GAGenome & c) { GABin2DecGenome & genome = (GABin2DecGenome &)c; float value=100.0; value *= genome.phenotype(0) * genome.phenotype(0) - genome.phenotype(1); value *= genome.phenotype(0) * genome.phenotype(0) - genome.phenotype(1); value += (1 - genome.phenotype(0))*(1 - genome.phenotype(0)); return(value); } // DeJong's third function is: // // f3(x1,x2,x3,x4,x5) = // 25 + floor(x1) + floor(x2) + floor(x3) + floor(x4) + floor(x5) // // where each x is in the range [-5.12,5.12] float DeJong3(GAGenome & c) { GABin2DecGenome & genome = (GABin2DecGenome &)c; float value=25.0; value -= floor(genome.phenotype(0)); value -= floor(genome.phenotype(1)); value -= floor(genome.phenotype(2)); value -= floor(genome.phenotype(3)); value -= floor(genome.phenotype(4)); return(value); } // DeJong's fourth function is: // // 30 // ___ // f4(xi) = \ { i * xi^4 + Gauss(0,1) } // /__ // i=1 // // where each x is in the range [-1.28,1.28] float DeJong4(GAGenome & c) { GABin2DecGenome & genome = (GABin2DecGenome &)c; float value = 0; for(int i=0; i<30; i++){ float v = genome.phenotype(i); v *= v; // xi^2 v *= v; // xi^4 v *= i; v += Gauss(0,1); value += v; } return(value); } // DeJong's fifth function is (Shekel's foxholes): // // // 25 1 // ___ --------------------------- // f5(x1,x2) = \ 2 // /__ ___ // j=1 j + \ (x[i] - a[i][j])^6 // /__ // i=1 // // where each x is in the range [-65.536,65.536] // static int a[2][25] ={ {-32, -16, 0, 16, 32, -32, -16, 0, 16, 32, -32, -16, 0, 16, 32, -32, -16, 0, 16, 32, -32, -16, 0, 16, 32 }, {-32, -32, -32, -32, -32, -16, -16, -16, -16, -16, 16, 16, 16, 16, 16, 32, 32, 32, 32, 32 } }; float DeJong5(GAGenome & c) { GABin2DecGenome & genome = (GABin2DecGenome &)c; float lowtot,prod,total=0.002; for(int j=0; j<25; j+=1) { lowtot=1.0 + (double)j; for(int i=0; i<2; i+=1) { prod=1.0; for(int power=0; power<6; power+=1) prod*=genome.phenotype(i)-a[i][j]; lowtot+=prod; } total+=1.0/lowtot; } return(500.0 - (1.0/total)); } // Return a number from gaussian distribution. This code was pinched from the // GNU libg++ Normal.cc implementation of a normal distribution. That is, in // turn, based on Simulation, Modelling & Analysis by Law & Kelton, pp259. // // My random number generator (actually just the system's) isn't as good as // that in the libg++, but this should be OK for this purpose. double Gauss(double mean, double variance){ for(;;) { double u1 = GARandomDouble(); double u2 = GARandomDouble(); double v1 = 2 * u1 - 1; double v2 = 2 * u2 - 1; double w = (v1 * v1) + (v2 * v2); if (w <= 1) { double y = sqrt( (-2 * log(w)) / w); double x1 = v1 * y; // double x2 = v2 * y; // we don't use this one return(x1 * sqrt(variance) + mean); } } } galib247/examples/ex2.C0100644003643600364360000001223110573535500014050 0ustar mwallmwall/* ---------------------------------------------------------------------------- ex2.C mbwall 28jul94 Copyright (c) 1995-1996 Massachusetts Institute of Technology DESCRIPTION: Example program for the SimpleGA class and Bin2DecGenome class. This program generates randomly a series of numbers then tries to match those values in a binary-to-decimal genome. We use a simple GA (with linear scaled fitness selection and non-steady-state population generation) and binary-to-decimal, 1D genomes. We also use the userData argument to the objective function. ---------------------------------------------------------------------------- */ #include #include #include #include #include #define cout STD_COUT float Objective(GAGenome &); int main(int argc, char **argv) { cout << "Example 2\n\n"; cout << "This program generates a sequence of random numbers then uses\n"; cout << "a simple GA and binary-to-decimal genome to match the\n"; cout << "sequence.\n\n"; // See if we've been given a seed to use (for testing purposes). When you // specify a random seed, the evolution will be exactly the same each time // you use that seed number. unsigned int seed = 0; for(int ii=1; ii #include #include #include #define cout STD_COUT // This is the objective function for computing Holland's 1993 ICGA version // of the Royal Road problem. It has been corrected per GAList volume 7 // number 23, 8/26/93. No bonus points are awarded for a given level until // it has been achieved (this fixes Holland's coding error in GAList). // Holland posed this problem as a challenge to test the // performance of genetic algorithms. He indicated that, with the parameter // settings of // // schemata size = 8 // bits between schemata = 7 // m* = 4 // U* = 1.0 // u = 0.3 // v = 0.02 // // he could attain royal_road_level 3 most of the time within // 10,000 function evaluations. He challenged other GA users to match or beat // that performance. He indicated that he used a population size of 512 to // obtain his solutions, and did NOT use a "simple genetic algorithm." // The genome for this problem is a single-dimension bit string with length // defined by the block size and gap size as: // // length = (blocksize+gapsize) * (2^K) // // where K= 1,2,3, or 4. Holland used K = 4. #define NBLOCKS 16 // this number is 2^K const int BLOCKSIZE=8; // block size - length of target schemata const int GAPSIZE=7; // gap size - number of bits between target schemata const int MSTAR=4; // Holland's m* - up to this many bits in low level // block gets reward const float USTAR=1.0; // Holland's U* - first block earns this const float RR_U=0.3; // Holland's u - increment for lowest level match const float RR_V=0.02; // Holland's v - reward/penalty per bit int nbits = (BLOCKSIZE+GAPSIZE)*NBLOCKS; int blockarray[NBLOCKS]; int highestLevel=0; float RoyalRoad(GAGenome & c){ GA1DBinaryStringGenome & genome = (GA1DBinaryStringGenome &)c; float score = 0.0; int total, i, j, index, n; // do the lowest level blocks first n = 0; for(i=0; i MSTAR && total < BLOCKSIZE) score -= (total-MSTAR)*RR_V; else if(total <= MSTAR) score += total * RR_V; if(total == BLOCKSIZE) { blockarray[i] = 1; n++; } else{ blockarray[i] = 0; } } // bonus for filled low-level blocks if(n > 0) score += USTAR + (n-1)*RR_U; // now do the higher-level blocks n = NBLOCKS; // n is now number of filled low level blocks int proceed = 1; // should we look at the next higher level? int level = 0; while ((n > 1) && proceed) { proceed = 0; total = 0; /* there are n valid blocks in the blockarray each time */ /* round, so n=2 is the last. */ for(i=0,index=0; i<(n/2)*2; i+=2,index++) { if(blockarray[i] == 1 && blockarray[i+1] == 1) { total++; proceed = 1; blockarray[index] = 1; } else{ blockarray[index] = 0; } } if(total > 0){ score += USTAR + (total-1)*RR_U; level++; } n /= 2; } if(highestLevel < level) highestLevel = level; return(score); } // The rest of this is standard for the GAlib examples. int main(int argc, char *argv[]) { cout << "Example 20\n\n"; cout << "Running Holland's Royal Road test problem with a genome that is\n"; cout << nbits << " bits long (" << NBLOCKS << " blocks). The parameters "; cout << "are as follows: \n\n"; cout << "\tblock size: " << BLOCKSIZE << "\n"; cout << "\t gap size: " << GAPSIZE << "\n"; cout << "\t m*: " << MSTAR << "\n"; cout << "\t u*: " << USTAR << "\n"; cout << "\t u: " << RR_U << "\n"; cout << "\t v: " << RR_V << "\n"; cout << "\n\n"; cout.flush(); // See if we've been given a seed to use (for testing purposes). When you // specify a random seed, the evolution will be exactly the same each time // you use that seed number. unsigned int seed = 0; for(int ii=1; ii #include #include #define cout STD_COUT #define endl STD_ENDL #define INSTANTIATE_REAL_GENOME #include float Objective1(GAGenome &); float Objective2(GAGenome &); float Objective3(GAGenome &); float Objective4(GAGenome &); int main(int argc, char** argv) { cout << "Example 21\n\n"; cout << "This example shows various uses of the allele set object\n"; cout << "in combination with the real number genome.\n\n"; cout.flush(); // See if we've been given a seed to use (for testing purposes). When you // specify a random seed, the evolution will be exactly the same each time // you use that seed number. unsigned int seed = 0; for(int ii=1; ii genome.gene(i-1)) value += 1.0; return value; } // This objective tries to maximize each element in the genome. float Objective4(GAGenome& g) { GARealGenome& genome = (GARealGenome&)g; float value=0.0; for(int i=0; i #include #include #include #define cout STD_COUT #define cerr STD_CERR #define endl STD_ENDL #define ofstream STD_OFSTREAM // force instantiations for compilers that do not do auto instantiation // for some compilers (e.g. metrowerks) this must come after any // specializations or you will get 'multiply-defined errors when you compile. #if !defined(GALIB_USE_AUTO_INST) #include GALIB_INSTANTIATION_PREFIX GA1DArrayGenome; #endif #ifndef M_PI #define M_PI 3.14159265358979323846 #endif #define OBJECTIVE Objective1 #define MIN_VALUE -100 #define MAX_VALUE 100 //#define OBJECTIVE Objective2 //#define MIN_VALUE -50 //#define MAX_VALUE 50 float Objective1(GAGenome&); float Objective2(GAGenome&); int Mutator(GAGenome&, float); void Initializer(GAGenome&); float Comparator(const GAGenome&, const GAGenome&); int Crossover(const GAGenome&, const GAGenome&, GAGenome*); // Here we define our own genetic algorithm class. This class is almost the // same as the steady-state genetic algorithm, but we modify the step method // (the one that does all the work) so that we do a slightly modified // replacement. We're only going to do a two-parents-make-one-child mating, // so we define our own crossover and use it rather than the standard one in // GAlib. typedef int (*SingleChildCrossover)(const GAGenome&,const GAGenome&,GAGenome*); class SharedOverlapGA : public GASteadyStateGA { public: GADefineIdentity("SharedOverlapGA", 200); SharedOverlapGA(const GAGenome& g) : GASteadyStateGA(g) {} virtual ~SharedOverlapGA() {} virtual void step(); SharedOverlapGA & operator++() { step(); return *this; } void crossover(SingleChildCrossover func) {crossFunction = func;} protected: SingleChildCrossover crossFunction; }; // This step method is similar to that of the regular steady-state genetic // algorithm, but here we generate only one child in a crossover, and we // do a slightly different type of replacement. Here we generate the new // individuals, insert them into the population, force a scaling to occur, // then remove the worst individuals. This is all done based on the scaled // (fitness) scores, not the raw (objective) scores. void SharedOverlapGA::step() { int i; GAGenome *mom, *dad; for(i=0; isize(); i++){ // takes care of odd population mom = &(pop->select()); dad = &(pop->select()); stats.numsel += 2; // keep track of number of selections if(GAFlipCoin(pCrossover())) stats.numcro += crossFunction(*mom, *dad, &tmpPop->individual(i)); else if(GARandomBit()) tmpPop->individual(i).copy(*mom); else tmpPop->individual(i).copy(*dad); stats.nummut += tmpPop->individual(i).mutate(pMutation()); } for(i=0; isize(); i++) pop->add(tmpPop->individual(i)); pop->evaluate(); // get info about current pop for next time pop->scale(); // remind the population to do its scaling for(i=0; isize(); i++) pop->destroy(GAPopulation::WORST, GAPopulation::SCALED); stats.update(*pop); // update the statistics by one generation } int main(int argc, char** argv) { cout << "Example 22\n\n"; cout << "This example shows how to derive your own genetic algorithm\n"; cout << "class. Here we use a custom, single-child crossover and a\n"; cout << "modified replacement strategy with overlapping populations.\n\n"; cout.flush(); // See if we've been given a seed to use (for testing purposes). When you // specify a random seed, the evolution will be exactly the same each time // you use that seed number. unsigned int seed = 0; for(int ii=1; ii genome(1, OBJECTIVE); genome.initializer(::Initializer); genome.mutator(::Mutator); genome.comparator(::Comparator); GASharing share(Comparator); SharedOverlapGA ga(genome); ga.crossover(Crossover); ga.scaling(share); ga.populationSize(100); ga.pReplacement(0.25); ga.nGenerations(500); ga.pMutation(0.01); ga.pCrossover(1.0); ga.scoreFilename("bog.dat"); // name of file for scores ga.scoreFrequency(10); // keep the scores of every 10th generation ga.flushFrequency(100); // specify how often to write the score to disk ga.selectScores(GAStatistics::AllScores); ga.parameters(argc, argv, gaTrue); // parse commands, complain if bogus args cout << "initializing...\n"; cout.flush(); ga.initialize(seed); // dump the initial population to file outfile.open(ifile, (STD_IOS_OUT | STD_IOS_TRUNC)); for(i=0; i& genome = (GA1DArrayGenome&)g; float v = genome.gene(0); float y = 100.0 * exp(-fabs(v) / 50.0) * (1.0 - cos(v * M_PI * 2.0 / 25.0)); if(v < MIN_VALUE || v > MAX_VALUE) y = 0; if(y < 0) y = 0; return y+0.00001; } float Objective2(GAGenome& g) { GA1DArrayGenome& genome = (GA1DArrayGenome&)g; float v = genome.gene(0) / 100.0; float y = 0.5 + 0.6 * sin(M_PI*v) + 0.2 * sin(3*M_PI*v) + 0.1 * sin(5*M_PI*v) + 0.02 * sin(7*M_PI*v) + 0.01 * sin(7*M_PI*v); if(v < -0.23 || v > 1.23) y = 0; if(y < 0) y = 0; return y+0.00001; } void Initializer(GAGenome& g) { GA1DArrayGenome& genome = (GA1DArrayGenome&)g; genome.gene(0, GARandomFloat(-100.0, 100.0)); } int Mutator(GAGenome& g, float pmut) { GA1DArrayGenome& genome = (GA1DArrayGenome&)g; int nmut = 0; if(GAFlipCoin(pmut)){ genome.gene(0, genome.gene(0) + GARandomFloat() * (GARandomFloat() - GARandomFloat())); nmut = 1; } return nmut; } int Crossover(const GAGenome& g1, const GAGenome& g2, GAGenome* c1) { GA1DArrayGenome& mom = (GA1DArrayGenome&)g1; GA1DArrayGenome& dad = (GA1DArrayGenome&)g2; GA1DArrayGenome& child = (GA1DArrayGenome&)*c1; float distance = 0.0, midpoint = 0.0; midpoint = (mom.gene(0) + dad.gene(0)) / 2; distance = fabs(mom.gene(0) - dad.gene(0)); child.gene(0, midpoint + distance * (GARandomFloat() - GARandomFloat())); return 1; } // You can change the factor to control how tightly the distance function // considers the spacing of two genomes. Higher numbers will give you a // tighter clustering at function peaks. #define FACTOR 800 float Comparator(const GAGenome& g1, const GAGenome& g2) { GA1DArrayGenome& a = (GA1DArrayGenome&)g1; GA1DArrayGenome& b = (GA1DArrayGenome&)g2; float val= exp( - (a.gene(0)-b.gene(0)) * (a.gene(0)-b.gene(0)) / FACTOR); if(1-val < 0 || 1-val > 1) cerr << "val: " << val << "\n"; return 1-val; } galib247/examples/ex23.C0100644003643600364360000000775410573535500014151 0ustar mwallmwall/* ---------------------------------------------------------------------------- ex23.C mbwall 5jan96 Copyright (c) 1995-1996 Massachusetts Institute of Technology DESCRIPTION: This example shows how to use max/min feature of GAlib to maximize or minimize your objective functions. ---------------------------------------------------------------------------- */ #include #include #include #include #define cout STD_COUT #define endl STD_ENDL #define ofstream STD_OFSTREAM #define INSTANTIATE_REAL_GENOME #include #ifndef M_PI #define M_PI 3.14159265358979323846 #endif #define MIN_VALUE -2 #define MAX_VALUE 2 #define INC 0.005 float Objective(GAGenome &); float Comparator(const GAGenome&, const GAGenome&); int main(int argc, char** argv) { cout << "Example 23\n\n"; cout << "This program tries to maximize or minimize, depending on the\n"; cout << "command line argument that you give it. Use the command-line\n"; cout << "argument 'mm -1' to minimize (the default for this example), or\n"; cout << "'mm 1' to maximize. The objective function is a simple \n"; cout << "sinusoidal.\n\n"; cout.flush(); // See if we've been given a seed to use (for testing purposes). When you // specify a random seed, the evolution will be exactly the same each time // you use that seed number. for(int jj=1; jj #include #include #include #define cout STD_COUT #define endl STD_ENDL #define ofstream STD_OFSTREAM #define INSTANTIATE_REAL_GENOME #include #define MIN_VALUE -2 #define MAX_VALUE 2 #define INC 0.005 #define THRESHOLD 0.5 #ifndef M_PI #define M_PI 3.14159265358979323846 #endif float Objective(GAGenome &); float Comparator(const GAGenome&, const GAGenome&); // Use any ID above 200 for the object's ID number. The selection scheme // takes care of keeping the population up-to-date - we only have to worry // about the selection method itself. This selector picks randomly, but only // from the upper half of the population (based on the scaled fitness scores). class FinickySelector : public GASelectionScheme { public: GADefineIdentity("FinickySelector", 273); FinickySelector(int w=GASelectionScheme::SCALED) : GASelectionScheme(w) { } FinickySelector(const FinickySelector& orig) { copy(orig); } FinickySelector& operator=(const FinickySelector& orig) { if(&orig != this) copy(orig); return *this; } virtual ~FinickySelector() { } virtual GASelectionScheme* clone() const { return new FinickySelector; } virtual GAGenome& select() const; }; GAGenome& FinickySelector::select() const { return pop->best(GARandomInt(0, pop->size()/2), GAPopulation::SCALED); } // This is the genetic algorithm that does the restricted mating. It is // similar to the steady state genetic algorithm, but we modify the selection // part of the step method to do the restricted mating. class RestrictedMatingGA : public GASteadyStateGA { public: GADefineIdentity("RestrictedMatingGA", 288); RestrictedMatingGA(const GAGenome& g) : GASteadyStateGA(g) {} virtual ~RestrictedMatingGA() {} virtual void step(); RestrictedMatingGA & operator++() { step(); return *this; } }; // This step method is similar to that of the regular steady-state genetic // algorithm, but here we select only individuals that are similar to each // other (based on what their comparators tell us). void RestrictedMatingGA::step() { int i; GAGenome *mom, *dad; // Generate the individuals in the temporary population from individuals in // the main population. We do a restrictive selection in which we only let // individuals that are dissimilar mate. We do a little count just to make // sure that we don't loop forever (just accept whatever we selected if we // can't find what we'd like). for(i=0; isize()-1; i+=2){ // takes care of odd population mom = &(pop->select()); int k=0; do { k++; dad = &(pop->select()); } while(mom->compare(*dad) < THRESHOLD && ksize()); stats.numsel += 2; // keep track of number of selections if(GAFlipCoin(pCrossover())){ stats.numcro += (*scross)(*mom, *dad, &tmpPop->individual(i), &tmpPop->individual(i+1)); } else{ tmpPop->individual( i ).copy(*mom); tmpPop->individual(i+1).copy(*dad); } stats.nummut += tmpPop->individual( i ).mutate(pMutation()); stats.nummut += tmpPop->individual(i+1).mutate(pMutation()); } if(tmpPop->size() % 2 != 0){ // do the remaining population member mom = &(pop->select()); dad = &(pop->select()); int k=0; do { k++; dad = &(pop->select()); } while(mom->compare(*dad) < THRESHOLD && ksize()); stats.numsel += 2; // keep track of number of selections if(GAFlipCoin(pCrossover())){ stats.numcro += (*scross)(*mom, *dad, &tmpPop->individual(i), (GAGenome*)0); } else{ if(GARandomBit()) tmpPop->individual( i ).copy(*mom); else tmpPop->individual( i ).copy(*dad); } stats.nummut += tmpPop->individual( i ).mutate(pMutation()); } // Now stick the new individuals into the population, force an evaluation, // force a scaling, then remove the worst individuals so that we keep a // constant population size. for(i=0; isize(); i++) pop->add(tmpPop->individual(i)); pop->evaluate(); // get info about current pop for next time pop->scale(); // remind the population to do its scaling for(i=0; isize(); i++) pop->destroy(GAPopulation::WORST, GAPopulation::SCALED); stats.update(*pop); // update the statistics by one generation } int main(int argc, char** argv) { cout << "Example 24\n\n"; cout << "This example illustrates how to derive your own genetic\n"; cout << "algorithm. This genetic algorithm does restricted mating and\n"; cout << "uses a selector slightly more finicky than a uniform random\n"; cout << "selector. The objective function is a simple sinusoidal.\n\n"; cout.flush(); // See if we've been given a seed to use (for testing purposes). When you // specify a random seed, the evolution will be exactly the same each time // you use that seed number. unsigned int seed = 0; for(int ii=1; ii #include #include #include #define cout STD_COUT #define endl STD_ENDL float Objective(GAGenome &); int main(int argc, char** argv) { cout << "Example 25\n\n"; cout << "This example uses a genetic algorithm with multiple populations.\n"; cout << endl; // See if we've been given a seed to use (for testing purposes). When you // specify a random seed, the evolution will be exactly the same each time // you use that seed number. unsigned int seed = 0; for(int ii=1; ii #include #include #include #include #define cout STD_COUT #define cerr STD_CERR #define endl STD_ENDL #define ostream STD_OSTREAM #define ifstream STD_IFSTREAM // Set this up for your favorite TSP. The sample one is a contrived problem // with the towns laid out in a grid (so it is easy to figure out what the // shortest distance is, and there are many different paths with the same // shortest path). File format is that used by the TSPLIB problems. You can // grab more problems from // // // Apologies for using fixed-length arrays. But this is an example, not // production code ;) #define MAX_TOWNS 50 #define TSP_FILE "tsp_rect_20.txt" float DISTANCE[MAX_TOWNS][MAX_TOWNS]; double x[MAX_TOWNS],y[MAX_TOWNS]; int ntowns = 0; // You can use either edge recombination crossover or partial match crossover. // Which one you select makes a HUGE difference in the performance of the // genetic algorithm. Only one of the two following lines should be commented. //#define XOVER PMXover // (Partial Match Crossover) #define XOVER ERXover // (Edge Recombination Crossover) float Objective(GAGenome&); int Mutator(GAGenome&, float); void Initializer(GAGenome&); float Comparator(const GAGenome&, const GAGenome&); int ERXover(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*); int PMXover(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*); void ERXOneChild(const GAGenome&, const GAGenome&, GAGenome*); int main(int argc, char** argv) { cout << "Example 26\n\n"; cout << "The Travelling Salesman Problem (TSP) demo program.\n" << endl; // See if we've been given a seed to use (for testing purposes). When you // specify a random seed, the evolution will be exactly the same each time // you use that seed number. unsigned int seed = 0; for(int ii=1; ii> dump; in >> x[ntowns]; in >> y[ntowns]; ntowns++; } while(!in.eof() && ntowns < MAX_TOWNS); in.close(); if(ntowns >= MAX_TOWNS) { cerr << "data file contains more towns than allowed for in the fixed\n"; cerr << "arrays. Recompile the program with larger arrays or try a\n"; cerr << "smaller problem.\n"; exit(1); } double dx,dy; for(int i=0;i genome(Objective); genome.initializer(::Initializer); genome.mutator(::Mutator); genome.comparator(::Comparator); genome.crossover(XOVER); GASteadyStateGA ga(genome); ga.minimize(); ga.pReplacement(1.0); ga.populationSize(100); ga.nGenerations(1000); ga.pMutation(0.1); ga.pCrossover(1.0); ga.selectScores(GAStatistics::AllScores); ga.parameters(argc, argv); cout << "initializing..."; cout.flush(); ga.initialize(seed); cout << "evolving..."; cout.flush(); while(!ga.done()) { ga.step(); if(ga.generation() % 10 == 0) { cout << ga.generation() << " "; cout.flush(); } } genome = ga.statistics().bestIndividual(); cout << "the shortest path found is " << genome.score() << "\n"; cout << "this is the distance from the sequence\n"; cout << genome << "\n\n"; cout << ga.statistics() << "\n"; return 0; } // Here are the genome operators that we want to use for this problem. // Thanks to Jan Kees IJspeert for isolating an order-of-evaluation problem // in the previous implementation of this function. float Objective(GAGenome& g) { GAListGenome & genome = (GAListGenome &)g; float dist = 0; if(genome.head()) { for(int i=0; i &child=(GAListGenome &)g; while(child.head()) child.destroy(); // destroy any pre-existing list int i,town; static int visit[MAX_TOWNS]; memset(visit, 0, MAX_TOWNS*sizeof(int)); town=GARandomInt(0,ntowns-1); visit[town]=1; child.insert(town,GAListBASE::HEAD); // the head node for( i=1; i &child=(GAListGenome &)g; register int n, i; if ((GARandomFloat() >= pmut) || (pmut <= 0)) return 0; n = child.size(); if (GARandomFloat()<0.5) { child.swap(GARandomInt(0,n-1),GARandomInt(0,n-1)); // swap only one time } else { int nNodes = GARandomInt(1,((int)(n/2-1))); // displace nNodes child.warp(GARandomInt(0,n-1)); // with or without GAList TmpList; // inversion for(i=0;i &mate1=(GAListGenome &)g1; GAListGenome &mate2=(GAListGenome &)g2; GAListGenome &sis=(GAListGenome &)*c1; int i,j,k,t1,t2,town; static char CM[MAX_TOWNS][MAX_TOWNS],visit[MAX_TOWNS]; memset(CM, 0, MAX_TOWNS*MAX_TOWNS*sizeof(char)); memset(visit, 0, MAX_TOWNS*sizeof(char)); while (sis.head()) sis.destroy(); // create connection matrix mate1.head(); for(j=0; j PossFollowList; GAList FollowersList[5]; while (PossFollowList.head()) PossFollowList.destroy(); for(k=0; k<5; k++) { while (FollowersList[k].head()) FollowersList[k].destroy(); } // select the following town with the minimal no of next folling towns int nPoss,nFollow; for(i=1; i &mom=(GAListGenome &)g1; GAListGenome &dad=(GAListGenome &)g2; int a = GARandomInt(0, mom.size()); int b = GARandomInt(0, dad.size()); int h; if (b &sis=(GAListGenome &)*c1; sis.GAList::copy(mom); GAListIter diter(dad); index = diter.warp(a); for(i=a; isize } } sis.head(); // set iterator to head of list nc += 1; } if(c2) { GAListGenome &sis=(GAListGenome &)*c2; sis.GAList::copy(mom); GAListIter diter(dad); index = diter.warp(a); for(i=a; isize } } sis.head(); // set iterator to head of list nc += 1; } return nc; } float Comparator(const GAGenome& g1, const GAGenome& g2) { GAListGenome &a = (GAListGenome &)g1; GAListGenome &b = (GAListGenome &)g2; int i,j,t1,t2; float dist=ntowns; static char CM1[MAX_TOWNS][MAX_TOWNS],CM2[MAX_TOWNS][MAX_TOWNS]; memset(CM1, 0, MAX_TOWNS*MAX_TOWNS*sizeof(char)); memset(CM2, 0, MAX_TOWNS*MAX_TOWNS*sizeof(char)); // create connection matrix CM1 a.head(); for(i=0; i int GAListGenome::write(ostream & os) const { int *cur, *head; GAListIter tmpiter(*this); if((head=tmpiter.head()) != 0) { os << *head << " "; for(cur=tmpiter.next(); cur && cur != head; cur=tmpiter.next()) os << *cur << " "; } return os.fail() ? 1 : 0; } // force instantiations for compilers that do not do auto instantiation // for some compilers (e.g. metrowerks) this must come after any // specializations or you will get 'multiply-defined errors when you compile. #if !defined(GALIB_USE_AUTO_INST) #include #include GALIB_INSTANTIATION_PREFIX GAList; GALIB_INSTANTIATION_PREFIX GAListGenome; #endif galib247/examples/ex27.C0100644003643600364360000003165710573535500014154 0ustar mwallmwall/* ---------------------------------------------------------------------------- ex27.C mbwall 24mar96 Copyright (c) 1995-1996 Massachusetts Institute of Technology The code for this example is adapted from an original implementation by Thomas Grueninger (from Uni Stuttgart, visiting scholar at MIT) DESCRIPTION: This example shows how to use the Deterministic Crowding genetic algorithm. You can specify one of 4 different functions (they are described in more detail later in this file). (This code was originally used with a 3D OpenGL-based program to illustrate the differences in convergence between various speciation methods. Believe me, it looks much better running in real-time in 3D, but, alas, there is not yet any standard 3D cross-platform API, so you get this instead.) ---------------------------------------------------------------------------- */ #include #include #include #include #include #define cout STD_COUT #define cerr STD_CERR #define endl STD_ENDL // force instantiations for compilers that do not do auto instantiation // for some compilers (e.g. metrowerks) this must come after any // specializations or you will get 'multiply-defined errors when you compile. #if !defined(GALIB_USE_AUTO_INST) #include #include GALIB_INSTANTIATION_PREFIX GAList; GALIB_INSTANTIATION_PREFIX GA1DArrayGenome; #endif // This is the class definition for the deterministic crowding genetic // algorithm. It is based upon the steady-state genetic algorithm, but we // modify the replacement so that it does deterministic crowding as described // by Goldberg (not in his book) and his students. class DCrowdingGA : public GASteadyStateGA { public: GADefineIdentity("DeterministicCrowdingGA", 241); DCrowdingGA(const GAGenome& g) : GASteadyStateGA(g) {} virtual ~DCrowdingGA() {} virtual void step(); DCrowdingGA & operator++() { step(); return *this; } }; void DCrowdingGA::step() { int i,*ip; float d1,d2; GAGenome *mom, *dad; GAList IndPool; while (IndPool.head()) IndPool.destroy(); for (i=0; isize(); i++) IndPool.insert(i); do { //select mom IndPool.warp(GARandomInt(0,IndPool.size()-1)); ip=IndPool.remove(); mom = &pop->individual(*ip); delete ip; //select dad IndPool.warp(GARandomInt(0,IndPool.size()-1)); ip=IndPool.remove(); dad = &pop->individual(*ip); delete ip; //create child stats.numsel += 2; stats.numcro += (*(mom->sexual()))(*mom, *dad, &tmpPop->individual(0), 0); stats.nummut += tmpPop->individual(0).mutate(pMutation()); stats.numeval += 1; //replace closest parent d1 = tmpPop->individual(0).compare(*mom); d2 = tmpPop->individual(0).compare(*dad); if (d1 < d2) { if (minmax == MINIMIZE) { if (tmpPop->individual(0).score() < mom->score()) { mom->copy(tmpPop->individual(0)); stats.numrep += 1; } } else { if (tmpPop->individual(0).score() > mom->score()) { mom->copy(tmpPop->individual(0)); stats.numrep += 1; } } } else { if (minmax == MINIMIZE) { if (tmpPop->individual(0).score() < dad->score()) { dad->copy(tmpPop->individual(0)); stats.numrep += 1; } } else { if (tmpPop->individual(0).score() > dad->score()) { dad->copy(tmpPop->individual(0)); stats.numrep += 1; } } } } while (IndPool.size()>1); pop->evaluate(gaTrue); stats.update(*pop); } // Set up the various 2-dimensional, real number functions that we will use. typedef float (*Function)(float, float); float Function1(float, float); float Function2(float, float); float Function3(float, float); float Function4(float, float); float ai[25],bi[25]; static int which = 0; static Function obj[] = { Function1, Function2, Function3, Function4 }; static float minx[] = {-6, -60, -500, -10 }; static float maxx[] = { 6, 60, 500, 10 }; static float miny[] = {-6, -60, -500, -10 }; static float maxy[] = { 6, 60, 500, 10 }; // These are the declarations for our genome operators (we do not use the // defaults from GAlib for this example). float Objective(GAGenome&); int Mutator(GAGenome&, float); void Initializer(GAGenome&); int Crossover(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*); float Comparator(const GAGenome&, const GAGenome&); int main(int argc, char** argv) { cout << "Example 27\n\n"; cout << "Deterministic crowding demonstration program.\n\n"; cout << "In addition to the standard GAlib command-line arguments,\n"; cout << "you can specify one of the four following functions:\n"; cout << " 0 - modified Himmelblau's function\n"; cout << " 1 - Foxholes (25)\n"; cout << " 2 - Schwefel's nasty (1 glob. Max bei (420.96/420.96)\n"; cout << " 3 - Mexican Hat (optimum at 0,0)\n"; cout << endl; int i; // See if we've been given a seed to use (for testing purposes). When you // specify a random seed, the evolution will be exactly the same each time // you use that seed number. for(i=1; i genome(2, Objective); genome.initializer(::Initializer); genome.mutator(::Mutator); genome.comparator(::Comparator); genome.crossover(::Crossover); DCrowdingGA ga(genome); ga.maximize(); ga.populationSize(100); ga.nGenerations(100); ga.pMutation(0.05); ga.pCrossover(1.0); ga.selectScores(GAStatistics::AllScores); ga.parameters(argc, argv, gaFalse); for (i=1; i= argc){ cerr << argv[0] << ": the function option needs a number.\n"; exit(1); } else{ which = atoi(argv[i]); continue; } } else if(strcmp("seed", argv[i]) == 0){ if(++i < argc) continue; continue; } else { cerr << argv[0] << ": unrecognized arguement: " << argv[i] << "\n\n"; cerr << "valid arguments include standard GAlib arguments plus:\n"; cerr << " f\tfunction to use (" << which << ")\n"; cerr << "\n"; exit(1); } } ga.evolve(); cout << "best individual is " << ga.statistics().bestIndividual() << "\n\n"; cout << ga.statistics() << "\n"; return 0; } /*****************************************************************************/ /* Type: 2D FUNCTION */ /* Name: Objective2D_1 */ /* Description: 2D tooth */ /* Boundaries: -6 < x < 6 */ /* -6 < y < 6 */ /* Source: modified Himmelblau's function from Deb, K. */ /* 'GA in multimodal function optimazation' Masters thesis */ /* TCGA Rep. 89002 / U. of Alabama */ /*****************************************************************************/ float Function1(float x, float y) { float z = -((x*x+y-11)*(x*x+y-11)+(x+y*y-7)*(x+y*y-7))/200 + 10; return z; } /*****************************************************************************/ /* Type: 2D FUNCTION */ /* Name: Objective2D_2 */ /* Description: Foxholes (25) */ /* Boundaries: -60 < x < 60 */ /* -60 < y < 60 */ /* Source: Shekel's Foxholes problem from De Jong's Diss.(1975) */ /* 'GA in multimodal function optimazation' Masters thesis */ /* TCGA Rep. 89002 / U. of Alabama */ /*****************************************************************************/ float Function2(float x, float y) { int i; float sum = 0; for (i=0; i<25; i++) { sum += (1 / (1 + i + pow((x-ai[i]),6) + pow((y-bi[i]),6))); } float z = 100.0 - (1 / (0.02 + sum)); return z; } /*****************************************************************************/ /* Type: 2D FUNCTION */ /* Name: Objective2D_3 */ /* Description: Schwefel's nasty (1 glob. Max bei (420.96/420.96) */ /* Boundaries: -500 < x < 500 */ /* -500 < y < 500 */ /* Source: Schwefel's function in Schoeneburg */ /*****************************************************************************/ float Function3(float x, float y) { float z = fabs(x) * sin(sqrt(fabs(x))) + fabs(y) * sin(sqrt(fabs(y))); //float z = 100 * ( sin(sqrt(fabs(x))) * sin(sqrt(fabs(y))) ); return (z); } /*****************************************************************************/ /* Type: 2D FUNCTION */ /* Name: Objective2D_4 */ /* Description: Mexican Hat */ /* Boundaries: -10 < x < 10 */ /* -10 < y < 10 */ /* Source: */ /*****************************************************************************/ float Function4(float x, float y) { float z = sin(sqrt(x*x + y*y))*sin(sqrt(x*x + y*y)) - 0.5; z /= ((1.0 + 0.001*(x*x + y*y))*(1.0 + 0.001*(x*x + y*y))); z = (0.5 - z); return (z); } // These are the operators that we'll use for the real number genome. float Objective(GAGenome& g) { GA1DArrayGenome& genome = (GA1DArrayGenome&)g; return (obj[which])(genome.gene(0), genome.gene(1)); } void Initializer(GAGenome& g) { GA1DArrayGenome& genome = (GA1DArrayGenome&)g; genome.gene(0, GARandomFloat(minx[which], maxx[which])); genome.gene(1, GARandomFloat(miny[which], maxy[which])); } int Mutator(GAGenome& g, float pmut) { GA1DArrayGenome& genome = (GA1DArrayGenome&)g; int nmut = 0; if(GAFlipCoin(pmut)){ genome.gene(0, genome.gene(0) + 10*GARandomFloat() * (GARandomFloat() - GARandomFloat())); genome.gene(1, genome.gene(1) + 10*GARandomFloat() * (GARandomFloat() - GARandomFloat())); nmut++; } if(genome.gene(0) < minx[which]) genome.gene(0, minx[which]); if(genome.gene(0) > maxx[which]) genome.gene(0, maxx[which]); if(genome.gene(1) < minx[which]) genome.gene(1, minx[which]); if(genome.gene(1) > maxx[which]) genome.gene(1, maxx[which]); return nmut; } int Crossover(const GAGenome& g1,const GAGenome& g2,GAGenome* c1,GAGenome* c2){ GA1DArrayGenome& mom = (GA1DArrayGenome&)g1; GA1DArrayGenome& dad = (GA1DArrayGenome&)g2; int n = 0; float distance = 0.0, midpoint = 0.0; if(c1) { GA1DArrayGenome& sis = (GA1DArrayGenome&)*c1; distance = midpoint = 0.0; midpoint = (mom.gene(0) + dad.gene(0)) / 2; distance = fabs(mom.gene(0) - dad.gene(0)); sis.gene(0, midpoint + distance * (GARandomFloat() - GARandomFloat())); midpoint = (mom.gene(1) + dad.gene(1)) / 2; distance = fabs(mom.gene(1) - dad.gene(1)); sis.gene(1, midpoint + distance * (GARandomFloat() - GARandomFloat())); if(sis.gene(0) < minx[which]) sis.gene(0, minx[which]); if(sis.gene(0) > maxx[which]) sis.gene(0, maxx[which]); if(sis.gene(1) < minx[which]) sis.gene(1, minx[which]); if(sis.gene(1) > maxx[which]) sis.gene(1, maxx[which]); n += 1; } if(c2) { GA1DArrayGenome& bro = (GA1DArrayGenome&)*c2; distance = midpoint = 0.0; midpoint = (mom.gene(0) + dad.gene(0)) / 2; distance = fabs(mom.gene(0) - dad.gene(0)); bro.gene(0, midpoint + distance * (GARandomFloat() - GARandomFloat())); midpoint = (mom.gene(1) + dad.gene(1)) / 2; distance = fabs(mom.gene(1) - dad.gene(1)); bro.gene(1, midpoint + distance * (GARandomFloat() - GARandomFloat())); if(bro.gene(0) < minx[which]) bro.gene(0, minx[which]); if(bro.gene(0) > maxx[which]) bro.gene(0, maxx[which]); if(bro.gene(1) < minx[which]) bro.gene(1, minx[which]); if(bro.gene(1) > maxx[which]) bro.gene(1, maxx[which]); n += 1; } return n; } float Comparator(const GAGenome& g1, const GAGenome& g2) { GA1DArrayGenome& a = (GA1DArrayGenome&)g1; GA1DArrayGenome& b = (GA1DArrayGenome&)g2; float valx=(a.gene(0)-b.gene(0)) * (a.gene(0)-b.gene(0)); float valy=(a.gene(1)-b.gene(1)) * (a.gene(1)-b.gene(1)); return sqrt(valx+valy); } galib247/examples/ex3.C0100644003643600364360000001202710573535500014054 0ustar mwallmwall/* ---------------------------------------------------------------------------- ex3.C mbwall 28jul94 Copyright (c) 1995-1996 Massachusetts Institute of Technology DESCRIPTION: Example program for the SimpleGA class and 2DBinaryStringGenome class. This program reads in a 2D pattern from a data file then tries to match the pattern in a 2D binary string genome. We use a simple GA (with linear scaled fitness selection and non-steady-state population generation) and 2D binary string genomes. This example also illustrates the use of the GAParameterList for setting default parameters on the genetic algorithm and for parsing the command line. ---------------------------------------------------------------------------- */ #include #include #include // the header for the GA we'll use #include // and the header for the genome we need #include #define cout STD_COUT #define cerr STD_CERR #define ifstream STD_IFSTREAM float objective(GAGenome &); int main(int argc, char *argv[]) { cout << "Example 3\n\n"; cout << "This program reads in a data file then runs a simple GA whose\n"; cout << "objective function tries to match the pattern of bits that are\n"; cout << "in the data file.\n\n"; // See if we've been given a seed to use (for testing purposes). When you // specify a random seed, the evolution will be exactly the same each time // you use that seed number. for(int ii=1; ii= argc){ cerr << argv[0] << ": the file option needs a filename.\n"; exit(1); } else{ sprintf(filename, argv[i]); continue; } } else if(strcmp("seed", argv[i]) == 0){ if(++i < argc) continue; continue; } else { cerr << argv[0] << ": unrecognized arguement: " << argv[i] << "\n\n"; cerr << "valid arguments include standard GAlib arguments plus:\n"; cerr << " f\tfilename from which to read (" << filename << ")\n"; cerr << "\n"; exit(1); } } // Read in the pattern from the specified file. File format is pretty simple: // two integers that give the height then width of the matrix, then the matrix // of 1's and 0's (with whitespace inbetween). ifstream inStream(filename); if(!inStream){ cerr << "Cannot open " << filename << " for input.\n"; exit(1); } int height, width; inStream >> height >> width; short **target = new short*[width]; for(i=0; i> target[i][j]; inStream.close(); // Print out the pattern to be sure we got the right one. cout << "input pattern:\n"; for(j=0; j #include // include the steady-state GA header #include // and the header for the genome we'll use #include #define cout STD_COUT float objective(GAGenome &); int main(int argc, char **argv) { cout << "Example 4\n\n"; cout << "This program tries to fill a 3DBinaryStringGenome with\n"; cout << "alternating 1s and 0s using a SteadyStateGA\n\n"; cout.flush(); // See if we've been given a seed to use (for testing purposes). When you // specify a random seed, the evolution will be exactly the same each time // you use that seed number. for(int ii=1; ii #include #include #include #include #include #include #define cout STD_COUT #define cerr STD_CERR #define istream STD_ISTREAM #define ostream STD_OSTREAM #define ifstream STD_IFSTREAM // This is the class definition for the new genome. The default operators are // defined as static member functions. They can be overridden if necessary by // anyone making an instance of this class - you don't need to derive a new // class to change the behaviour of one or two of its operators. class CompositeGenome : public GAGenome { public: GADefineIdentity("CompositeGenome", 201); static void CompositeInitializer(GAGenome&); static int CompositeMutator(GAGenome&, float); static float CompositeComparator(const GAGenome&, const GAGenome&); static int CompositeCrossover(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*); public: CompositeGenome(int, int, GABin2DecPhenotype&, GAGenome::Evaluator f=NULL, void* u=NULL); CompositeGenome(const CompositeGenome & orig); CompositeGenome& operator=(const GAGenome& g); virtual ~CompositeGenome(); virtual GAGenome* clone(GAGenome::CloneMethod) const ; virtual void copy(const GAGenome & c); virtual int equal(const GAGenome& g) const; virtual int read(istream & is); virtual int write(ostream & os) const; GA2DBinaryStringGenome & binstr() const {return *str;} GABin2DecGenome & bin2dec() const {return *b2d;} protected: GA2DBinaryStringGenome *str; GABin2DecGenome *b2d; }; // Member functions for the composite genome object CompositeGenome:: CompositeGenome(int element, int bond, GABin2DecPhenotype& p, GAGenome::Evaluator f, void* u) : GAGenome( CompositeInitializer, CompositeMutator, CompositeComparator) { evaluator(f); userData(u); crossover(CompositeCrossover); str = new GA2DBinaryStringGenome(element, bond, f, u); b2d = new GABin2DecGenome(p, f, u); } CompositeGenome::CompositeGenome(const CompositeGenome & orig) { str = new GA2DBinaryStringGenome(orig.binstr()); b2d = new GABin2DecGenome(orig.bin2dec()); copy(orig); } CompositeGenome& CompositeGenome::operator=(const GAGenome& g) { copy(g); return *this; } CompositeGenome::~CompositeGenome() { delete str; delete b2d; } GAGenome* CompositeGenome::clone(GAGenome::CloneMethod) const { return new CompositeGenome(*this); } void CompositeGenome::copy(const GAGenome & c){ if(&c != this && sameClass(c)){ GAGenome::copy(c); CompositeGenome & bc = (CompositeGenome &)c; str->copy(*(bc.str)); b2d->copy(*(bc.b2d)); } } int CompositeGenome::equal(const GAGenome& g) const { CompositeGenome& genome = (CompositeGenome&)g; return ((*str == *genome.str) && (*b2d == *genome.b2d)); } int CompositeGenome::read(istream & is) { is >> *str >> *b2d; return is.fail() ? 1 : 0; } int CompositeGenome::write(ostream & os) const { int i,j; for(j=0; jheight(); j++){ for(i=0; iwidth(); i++) os << (str->gene(i,j) == 1 ? '*' : ' ') << " "; os << "\n"; } os << "\n" << *b2d << "\n"; return os.fail() ? 1 : 0; } // These are the default initialization, mutation, and comparator operators for // this genome class. They are defined as static functions of the composite // genome class and they're defaults for the class. But they can be overridden // on any instance of the genome. // The initializer just calls the initializer for each of the genomes that are // in the composite genome. // I would have used simply 'Initializer', 'Mutator', etc rather than // 'CompositeInitializer' but old versions of g++ are brain-dead and don't // get the encapsulation properly. void CompositeGenome::CompositeInitializer(GAGenome & c) { CompositeGenome & child = (CompositeGenome &)c; child.binstr().initialize(); child.bin2dec().initialize(); child._evaluated = gaFalse; } // The mutator just calls the mutator for each of the component genomes. int CompositeGenome::CompositeMutator(GAGenome & c, float pmut) { CompositeGenome & child = (CompositeGenome &)c; int nmut = child.binstr().mutate(pmut) + child.bin2dec().mutate(pmut); if(nmut) child._evaluated = gaFalse; return nmut; } // The comparator just calls the comparators for each of the component genomes, // then averages the score. float CompositeGenome::CompositeComparator(const GAGenome& a, const GAGenome& b) { CompositeGenome& sis = (CompositeGenome &)a; CompositeGenome& bro = (CompositeGenome &)b; return 0.5 * (sis.binstr().compare(bro) + sis.bin2dec().compare(bro)); } // The crossover operator invokes the crossover for each of the genomes in the // composite genome. We use sexual crossover only, and we do not test to see // if no crossover has been assigned. int CompositeGenome:: CompositeCrossover(const GAGenome& a, const GAGenome& b, GAGenome* c, GAGenome* d){ CompositeGenome& mom = (CompositeGenome&)a; CompositeGenome& dad = (CompositeGenome&)b; int n=0; GAGenome::SexualCrossover strcross = mom.str->sexual(); GAGenome::SexualCrossover b2dcross = mom.b2d->sexual(); if(c && d){ CompositeGenome& sis = (CompositeGenome&)*c; CompositeGenome& bro = (CompositeGenome&)*d; (*strcross)(mom.binstr(), dad.binstr(), &sis.binstr(), &bro.binstr()); (*b2dcross)(mom.bin2dec(),dad.bin2dec(), &sis.bin2dec(), &bro.bin2dec()); sis._evaluated = gaFalse; bro._evaluated = gaFalse; n = 2; } else if(c){ CompositeGenome& sis = (CompositeGenome&)*c; (*strcross)(mom.binstr(), dad.binstr(), &sis.binstr(), 0); (*b2dcross)(mom.bin2dec(), dad.bin2dec(), &sis.bin2dec(), 0); sis._evaluated = gaFalse; n = 1; } else if(d){ CompositeGenome& bro = (CompositeGenome&)*d; (*strcross)(mom.binstr(), dad.binstr(), 0, &bro.binstr()); (*b2dcross)(mom.bin2dec(), dad.bin2dec(), 0, &bro.bin2dec()); bro._evaluated = gaFalse; n = 1; } return n; } // This object is a container for the data that we are supposed to match in // our objective function. typedef struct _CompositeData { short ** str; float * b2d; } CompositeData; // In this objective function we try to match the pattern in the 2D part of the // genome and match the sequence of values in the binary-to-decimal part of the // genome. The overall score is the sum of both parts. float Objective(GAGenome & g) { CompositeGenome & genome = (CompositeGenome &)g; GA2DBinaryStringGenome & str = genome.binstr(); GABin2DecGenome & b2d = genome.bin2dec(); int i; short **pattern = ((CompositeData *)g.userData())->str; float val1=0.0; for(i=0; ib2d; float val2=b2d.nPhenotypes(); for(i=0; i= argc){ cerr << argv[0] << ": you must specify a filename.\n"; exit(1); } else{ sprintf(filename1, argv[i]); continue; } } else if(strcmp("values", argv[i]) == 0){ if(++i >= argc){ cerr << argv[0] << ": you must specify a filename.\n"; exit(1); } else{ sprintf(filename2, argv[i]); continue; } } else if(strcmp("seed", argv[i]) == 0){ if(++i < argc) continue; continue; } else { cerr << argv[0] << ": unrecognized arguement: " << argv[i] << "\n\n"; cerr << "valid arguements include standard GAlib flags plus:\n"; cerr << " graph\tname of graph filename (" << filename1 << ")\n"; cerr << " values\tname of values filename (" << filename2 << ")\n"; cerr << "\n"; exit(1); } } ifstream infile; // First we read in the pattern for the 2DBinStr genome. // File format is pretty simple: // two integers that give the height then width of the matrix, // then the matrix of 1's and 0's (with whitespace inbetween). infile.open(filename1); if(!infile){ cerr << "Cannot open " << filename1 << " for input.\n"; exit(1); } int height, width; infile >> height; infile >> width; short **target = new short*[width]; for(i=0; i> target[i][j]; infile.close(); // Now we read in a sequence of numbers that the Bin2Dec genome is supposed // to match for its objective. File format is // pretty simple: a single integer that tells how many numbers will follow, // then the sequence of numbers. infile.open(filename2); if(!infile){ cerr << "Cannot open " << filename2 << " for input.\n"; exit(1); } infile >> n; float *sequence = new float[n]; for(i=0; i> sequence[i]; infile.close(); // Print out the pattern and sequence. cout << "input pattern:\n"; for(j=0; j #include #include #include #define cout STD_COUT #define ostream STD_OSTREAM // The objective function is declared here and defined below. float objective(GAGenome &); // This is the declaration for the initialization operator for our trees. void TreeInitializer(GAGenome &); // This is a recursive function that will be used in the 'write' method for // our tree genomes. void WriteNode(ostream & os, GANode * n); int main(int argc, char *argv[]) { cout << "Example 6\n\n"; cout << "This example uses a SteadyState GA and Tree genome. It\n"; cout << "tries to maximize the size of the tree genomes that it\n"; cout << "contains. The genomes contain ints in its nodes.\n\n"; cout.flush(); // See if we've been given a seed to use (for testing purposes). When you // specify a random seed, the evolution will be exactly the same each time // you use that seed number. unsigned int seed = 0; for(int i=1; i genome(objective); genome.initializer(TreeInitializer); genome.mutator(GATreeGenome::SwapSubtreeMutator); GASteadyStateGA ga(genome); ga.parameters(params); ga.evolve(seed); genome = ga.statistics().bestIndividual(); // cout << "the ga generated this tree:\n" << genome << "\n"; cout << genome.size() << " nodes, " << genome.depth() << " levels deep.\n"; cout << "best of generation data are in '" << ga.scoreFilename() << "'\n"; return 0; } /* ---------------------------------------------------------------------------- Objective function All we do in this objective function is try to maximize the size of the tree. Just return the tree size. This means that if you run this objective function for many generations you'll run out of memory! There is no limit to tree or list sizes built-in to the GA library. ---------------------------------------------------------------------------- */ float objective(GAGenome & c) { GATreeGenome & genome = (GATreeGenome &)c; return genome.size(); } /* ---------------------------------------------------------------------------- Here is the initializer for our genomes. It builds a tree of n items of type int. Notice that we first destroy any tree that is already in the genome before we do our initialization. This is so that the genomes can be re-used. When you re-run a GA, it does not destroy the individuals in the population - it reuses them. Thus, the initializer must make sure that the genome is cleaned up before it tries to initialize it. ---------------------------------------------------------------------------- */ void TreeInitializer(GAGenome & c) { GATreeGenome &child=(GATreeGenome &)c; // destroy any pre-existing tree child.root(); child.destroy(); // Create a new tree with depth of 'depth' and each eldest node containing // 'n' children (the other siblings have none). int depth=2, n=3, count=0; child.insert(count++,GATreeBASE::ROOT); for(int i=0; i * n) { if(!n) return; GANodeBASE * node = (GANodeBASE *)n; os.width(10); os << ((GANode *)node)->contents << " "; os.width(10); if(node->parent) os << ((GANode *)node->parent)->contents << " "; else os << "." << " "; os.width(10); if(node->child) os << ((GANode *)node->child)->contents << " "; else os << "." << " "; os.width(10); if(node->next) os << ((GANode *)node->next)->contents << " "; else os << "." << " "; os.width(10); if(node->prev) os << ((GANode *)node->prev)->contents << "\n"; else os << ".\n"; WriteNode(os, (GANode *)node->child); for(GANodeBASE * tmp=node->next; tmp && tmp != node; tmp=tmp->next){ os.width(10); os << ((GANode *)tmp)->contents << " "; os.width(10); if(tmp->parent) os << ((GANode *)tmp->parent)->contents << " "; else os << "." << " "; os.width(10); if(tmp->child) os << ((GANode *)tmp->child)->contents << " "; else os << "." << " "; os.width(10); if(tmp->next) os << ((GANode *)tmp->next)->contents << " "; else os << "." << " "; os.width(10); if(tmp->prev) os << ((GANode *)tmp->prev)->contents << "\n"; else os << ".\n"; WriteNode(os, (GANode *)tmp->child); } } template<> int GATreeGenome::write(ostream & os) const { os << " node parent child next prev\n"; WriteNode(os, (GANode *)rt); return os.fail() ? 1 : 0; } // force instantiations for compilers that do not do auto instantiation // for some compilers (e.g. metrowerks) this must come after any // specializations or you will get 'multiply-defined errors when you compile. #if !defined(GALIB_USE_AUTO_INST) #include #include GALIB_INSTANTIATION_PREFIX GATreeGenome; GALIB_INSTANTIATION_PREFIX GATree; #endif galib247/examples/ex7.C0100644003643600364360000001762410573535500014070 0ustar mwallmwall/* ---------------------------------------------------------------------------- ex7.C mbwall 19jan95 Copyright 1995-1996 Massachusetts Institute of Technology DESCRIPTION: This example functions the same way as example 3, but this example shows how to use some of the other member functions in the GA library. We also do a few more fancy things with the genome (ie use the read/write methods). ---------------------------------------------------------------------------- */ #include #include #include #include #define cout STD_COUT #define cerr STD_CERR #define ifstream STD_IFSTREAM float objective(GAGenome &); int main(int argc, char *argv[]) { cout << "Example 7\n\n"; cout << "This program reads in a data file then runs a steady-state GA \n"; cout << "whose objective function tries to match the pattern of bits that\n"; cout << "are in the data file.\n\n"; // See if we've been given a seed to use (for testing purposes). When you // specify a random seed, the evolution will be exactly the same each time // you use that seed number. for(int ii=1; ii= argc){ cerr << argv[0] << ": the data file option needs a filename.\n"; exit(1); } else{ sprintf(datafile, argv[i]); continue; } } else if(strcmp("pfile", argv[i]) == 0){ if(++i >= argc){ cerr << argv[0] << ": the parameters file option needs a filename.\n"; exit(1); } else{ sprintf(parmfile, argv[i]); params.read(parmfile); continue; } } else if(strcmp("seed", argv[i]) == 0){ if(++i < argc) continue; continue; } else { cerr << argv[0] << ": unrecognized arguement: " << argv[i] << "\n\n"; cerr << "valid arguements include GAlib arguments plus:\n"; cerr << " dfile\tdata file from which to read (" << datafile << ")\n"; cerr << " pfile\tparameters file (" << parmfile << ")\n\n"; cerr << "default parameters are:\n" << params << "\n\n"; exit(1); } } // Read in the pattern from the specified file. File format is pretty simple: // two integers that give the height then width of the matrix, then the matrix // of 1's and 0's (with whitespace inbetween). // Here we use a binary string genome to store the desired pattern. This // shows how you can read in directly from a stream into a genome. (This can // be useful in a population initializer when you want to bias your population) ifstream inStream(datafile); if(!inStream){ cerr << "Cannot open " << datafile << " for input.\n"; exit(1); } int height, width; inStream >> height >> width; GA2DBinaryStringGenome target(width, height); inStream >> target; inStream.close(); // Print out the pattern to be sure we got the right one. cout << "input pattern:\n"; for(j=0; jgene(i,j)); return(value); } galib247/examples/ex8.C0100644003643600364360000001623110573535500014062 0ustar mwallmwall/* ---------------------------------------------------------------------------- ex8.C mbwall 14jan95 Copyright 1995-1996 Massachusetts Institute of Technology DESCRIPTION: Example program for the list genome. This example contains the code to run a genetic algorithm with a list genome. This program illustrates how to specialize member functions of the template classes. Here we specialize the default write() method so that we get the contents of the nodes rather than the pointers to the node contents. You can specialize most functions of a template class (as long as they are not inlined). The objective function for this example returns both positive and negative values, depending on the genome it is evaluting. So the example also shows how to use the sigma truncation scaling method to handle the mixed scores. ---------------------------------------------------------------------------- */ #include #include #include #include #define cout STD_COUT #define ostream STD_OSTREAM // Objective function and initializer declarations. float objective(GAGenome &); void ListInitializer(GAGenome &); int main(int argc, char *argv[]) { cout << "Example 8\n\n"; cout << "This program runs a steady-state GA whose objective function\n"; cout << "tries to maximize the size of the list and tries to make lists\n"; cout << "that contain the number 101 in the nodes. The lists contain\n"; cout << "ints in the nodes.\n\n"; cout.flush(); // See if we've been given a seed to use (for testing purposes). When you // specify a random seed, the evolution will be exactly the same each time // you use that seed number. for(int i=1; i genome(objective); genome.initializer(ListInitializer); // genome.mutator(GAListGenome::SwapMutator); genome.mutator(GAListGenome::DestructiveMutator); // Now that we have a genome, we use it to create our GA. After creating the // GA we set the parameters and tell the GA to use sigma truncation scaling // rather than the default (linear scaling). Set the crossover to single // point crossover. The genetic algorithm handles crossover since genomes // don't know about other genomes. We could set the crossover on the genome // if we wanted - either way will work. GASteadyStateGA ga(genome); GASigmaTruncationScaling scale; ga.scaling(scale); ga.crossover(GAListGenome::OnePointCrossover); // Set the default parameters we want to use, then check the command line for // other arguments that might modify these. ga.set(gaNpopulationSize, 40); // population size ga.set(gaNpCrossover, 0.6); // probability of crossover ga.set(gaNpMutation, 0.05); // probability of mutation ga.set(gaNnGenerations, 50); // number of generations ga.set(gaNscoreFrequency, 1); // how often to record scores ga.set(gaNflushFrequency, 10); // how often to dump scores to file ga.set(gaNselectScores, // which scores should we track? GAStatistics::Maximum|GAStatistics::Minimum|GAStatistics::Mean); ga.set(gaNscoreFilename, "bog.dat"); ga.parameters(argc, argv); // Evolve the genetic algorithm then dump out the results of the run. ga.evolve(); genome = ga.statistics().bestIndividual(); // cout << "the ga generated the list:\n" << genome << "\n"; cout << "the list contains " << genome.size() << " nodes\n"; cout << "the ga used the parameters:\n" << ga.parameters() << "\n"; return 0; } /* ---------------------------------------------------------------------------- Objective function There is no limit to the size of a list (only the memory you have on your computer). This objective function tries to build a list that contains the number 101 in all of its nodes. If we don't put some control on this objective then the list will grow without bound. So we dampen it a bit with a penalty for large size. However, this will make the score go negative, so we must use a scaling object that allows negative objective scores. We could get lists with no contents, so we have to check for that. Just make sure that head has contents. If it does, then the rest of the genome will. When we access the node contents we have to dereference the member functions. For example, we do *chrom.head() not chrom.head(). This is because the member functions return a pointer to the node's contents, not the actual contents. ---------------------------------------------------------------------------- */ float objective(GAGenome & c) { GAListGenome & genome = (GAListGenome &)c; int count=0; if(!genome.head()) return 0; count = (*genome.head() == 101) ? 1 : 0; // move to head of the list for(int i=1; i &child=(GAListGenome &)c; while(child.head()) child.destroy(); // destroy any pre-existing list int n=75; child.insert(100,GAListBASE::HEAD); for(int i=0; i int GAListGenome::write(ostream & os) const { int *cur, *head; GAListIter tmpiter(*this); if((head=tmpiter.head()) != NULL) os << *head << " "; for(cur=tmpiter.next(); cur && cur != head; cur=tmpiter.next()) os << *cur << " "; return os.fail() ? 1 : 0; } // force instantiations for compilers that do not do auto instantiation // for some compilers (e.g. metrowerks) this must come after any // specializations or you will get 'multiply-defined errors when you compile. #if !defined(GALIB_USE_AUTO_INST) #include #include GALIB_INSTANTIATION_PREFIX GAList; GALIB_INSTANTIATION_PREFIX GAListGenome; #endif galib247/examples/ex9.C0100644003643600364360000000556410573535500014072 0ustar mwallmwall/* ---------------------------------------------------------------------------- ex9.C mbwall 10apr95 Copyright 1995-1996 Massachusetts Institute of Technology DESCRIPTION: Sample program that illustrates how to use a GA to find the maximum value of a continuous function in two variables. This program uses a binary-to- decimal genome. ---------------------------------------------------------------------------- */ #include #include #include #define cout STD_COUT float objective(GAGenome &); int main(int argc, char **argv) { cout << "Example 9\n\n"; cout << "This program finds the maximum value in the function\n"; cout << " y = - x1^2 - x2^2\n"; cout << "with the constraints\n"; cout << " -5 <= x1 <= 5\n"; cout << " -5 <= x2 <= 5\n"; cout << "\n\n"; cout.flush(); // See if we've been given a seed to use (for testing purposes). When you // specify a random seed, the evolution will be exactly the same each time // you use that seed number. unsigned int seed = 0; for(int i=1; i #include #include AllocRing::AllocRing(int max) :n(max), current(0), nodes(new AllocQNode[max]) { for (int i = 0; i < n; ++i) { nodes[i].ptr = 0; nodes[i].sz = 0; } } int AllocRing::find(void* p) { if (p == 0) return -1; for (int i = 0; i < n; ++i) if (nodes[i].ptr == p) return i; return -1; } void AllocRing::clear() { for (int i = 0; i < n; ++i) { if (nodes[i].ptr != 0) { delete(nodes[i].ptr); nodes[i].ptr = 0; } nodes[i].sz = 0; } current = 0; } void AllocRing::free(void* p) { int idx = find(p); if (idx >= 0) { delete nodes[idx].ptr; nodes[idx].ptr = 0; } } AllocRing::~AllocRing() { clear(); } int AllocRing::contains(void* p) { return find(p) >= 0; } static inline unsigned int good_size(unsigned int s) { unsigned int req = s + 4; unsigned int good = 8; while (good < req) good <<= 1; return good - 4; } void* AllocRing::alloc(int s) { unsigned int size = good_size(s); void* p; if (nodes[current].ptr != 0 && nodes[current].sz >= int(size) && nodes[current].sz < int(4 * size)) p = nodes[current].ptr; else { if (nodes[current].ptr != 0) operator delete (nodes[current].ptr); p = operator new (size); nodes[current].ptr = p; nodes[current].sz = size; } ++current; if (current >= n) current = 0; return p; } galib247/examples/gnu/AllocRing.h0100644003643600364360000000324010573535475016075 0ustar mwallmwall// This may look like C code, but it is really -*- C++ -*- /* Copyright (C) 1989 Free Software Foundation written by Doug Lea (dl@rocky.oswego.edu) This file is part of the GNU C++ Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _AllocRing_h #ifdef __GNUG__ #pragma interface #endif #define _AllocRing_h 1 /* An AllocRing holds the last n malloc'ed strings, reallocating/reusing one only when the queue wraps around. It thus guarantees that the last n allocations are intact. It is useful for things like I/O formatting where reasonable restrictions may be made about the number of allowable live allocations before auto-deletion. */ class AllocRing { struct AllocQNode { void* ptr; int sz; }; AllocQNode* nodes; int n; int current; int find(void* p); public: AllocRing(int max); ~AllocRing(); void* alloc(int size); int contains(void* ptr); void clear(); void free(void* p); }; #endif galib247/examples/gnu/bitand.c0100644003643600364360000000323310573535475015461 0ustar mwallmwall/* Copyright (C) 1994 Free Software Foundation This file is part of the GNU BitString Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this library; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. As a special exception, if you link this library with files compiled with a GNU compiler to produce an executable, this does not cause the resulting executable to be covered by the GNU General Public License. This exception does not however invalidate any other reasons why the executable file might be covered by the GNU General Public License. */ /* Written by Per Bothner (bothner@cygnus.com). */ #include "bitprims.h" /* Copy LENGTH bits from (starting at SRCBIT) into pdst starting at DSTBIT. This will work even if psrc & pdst overlap. */ void /* _BS_and (pdst, dstbit, psrc, srcbit, length) register _BS_word* pdst; int dstbit; register const _BS_word* psrc; int srcbit; _BS_size_t length; */ _BS_and (register _BS_word* pdst, int dstbit, register const _BS_word* psrc, int srcbit, _BS_size_t length) { #define COMBINE(dst, src) (dst) & (src) #include "bitdo2.h" } galib247/examples/gnu/bitany.c0100644003643600364360000000273110573535475015510 0ustar mwallmwall/* Copyright (C) 1994 Free Software Foundation This file is part of the GNU BitString Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this library; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. As a special exception, if you link this library with files compiled with a GNU compiler to produce an executable, this does not cause the resulting executable to be covered by the GNU General Public License. This exception does not however invalidate any other reasons why the executable file might be covered by the GNU General Public License. */ /* Written by Per Bothner (bothner@cygnus.com) */ #include "bitprims.h" int /* _BS_any (ptr, offset, length) register const _BS_word *ptr; int offset; _BS_size_t length; */ _BS_any (register const _BS_word *ptr, int offset, _BS_size_t length) { #undef DOIT #define DOIT(WORD, MASK) if ((WORD) & (MASK)) return 1; #include "bitdo1.h" return 0; } galib247/examples/gnu/bitblt.c0100644003643600364360000000626210573535475015505 0ustar mwallmwall/* Copyright (C) 1994 Free Software Foundation This file is part of the GNU BitString Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this library; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. As a special exception, if you link this library with files compiled with a GNU compiler to produce an executable, this does not cause the resulting executable to be covered by the GNU General Public License. This exception does not however invalidate any other reasons why the executable file might be covered by the GNU General Public License. */ /* Written by Per Bothner (bothner@cygnus.com). Based on ideas in the X11 MFB server. */ #include "bitprims.h" #define ONES ((_BS_word)(~0)) /* Copy LENGTH bits from (starting at SRCBIT) into pdst starting at DSTBIT. This will work even if psrc & pdst overlap. */ void /* _BS_blt (op, pdst, dstbit, psrc, srcbit, length) enum _BS_alu op; register _BS_word* pdst; int dstbit; register const _BS_word* psrc; int srcbit; _BS_size_t length; */ _BS_blt (enum _BS_alu op, register _BS_word* pdst, int dstbit, register const _BS_word* psrc, int srcbit, _BS_size_t length) { _BS_word ca1, cx1, ca2, cx2; switch (op) { case _BS_alu_clear: _BS_clear (pdst, dstbit, length); return; case _BS_alu_and: _BS_and (pdst, dstbit, psrc, srcbit, length); return; case _BS_alu_andReverse: ca1 = ONES; cx1 = 0; ca2 = ONES; cx2 = 0; break; case _BS_alu_copy: _BS_copy (pdst, dstbit, psrc, srcbit, length); return; case _BS_alu_andInverted: ca1 = ONES; cx1 = ONES; ca2 = 0; cx2 = 0; break; case _BS_alu_noop: return; case _BS_alu_xor: _BS_xor (pdst, dstbit, psrc, srcbit, length); return; case _BS_alu_or: ca1 = ONES; cx1 = ONES; ca2 = ONES; cx2 = 0; break; case _BS_alu_nor: ca1 = ONES; cx1 = ONES; ca2 = ONES; cx2 = ONES; break; case_BS_alu_equiv: ca1 = 0; cx1 = ONES; ca2 = ONES; cx2 = ONES; break; case _BS_alu_invert: _BS_invert (pdst, dstbit, length); return; case _BS_alu_orReverse: ca1 = ONES; cx1 = ONES; ca2 = 0; cx2 = ONES; break; case _BS_alu_copyInverted: ca1 = 0; cx1 = 0; ca2 = ONES; cx2 = ONES; break; case _BS_alu_orInverted: ca1 = ONES; cx1 = 0; ca2 = ONES; cx2 = ONES; break; case _BS_alu_nand: ca1 = ONES; cx1 = 0; ca2 = 0; cx2 = ONES; break; case _BS_alu_set: _BS_set (pdst, dstbit, length); return; } { #define COMBINE(dst, src) ((dst) & ((src) & ca1 ^ cx1) ^ ((src) & ca2 ^ cx2)) #include "bitdo2.h" } } galib247/examples/gnu/bitclear.c0100644003643600364360000000267710573535475016020 0ustar mwallmwall/* Copyright (C) 1994 Free Software Foundation This file is part of the GNU BitString Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this library; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. As a special exception, if you link this library with files compiled with a GNU compiler to produce an executable, this does not cause the resulting executable to be covered by the GNU General Public License. This exception does not however invalidate any other reasons why the executable file might be covered by the GNU General Public License. */ /* Written by Per Bothner (bothner@cygnus.com) */ #include "bitprims.h" void /* _BS_clear (ptr, offset, length) register _BS_word *ptr; int offset; _BS_size_t length; */ _BS_clear (register _BS_word *ptr, int offset, _BS_size_t length) { #undef DOIT #define DOIT(WORD, MASK) ((WORD) &= ~(MASK)) #include "bitdo1.h" } galib247/examples/gnu/bitcopy.c0100644003643600364360000000323110573535475015667 0ustar mwallmwall/* Copyright (C) 1994 Free Software Foundation This file is part of the GNU BitString Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this library; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. As a special exception, if you link this library with files compiled with a GNU compiler to produce an executable, this does not cause the resulting executable to be covered by the GNU General Public License. This exception does not however invalidate any other reasons why the executable file might be covered by the GNU General Public License. */ /* Written by Per Bothner (bothner@cygnus.com). */ #include "bitprims.h" /* Copy LENGTH bits from (starting at SRCBIT) into pdst starting at DSTBIT. This will work even if psrc & pdst overlap. */ void /* _BS_copy (pdst, dstbit, psrc, srcbit, length) register _BS_word* pdst; int dstbit; register const _BS_word* psrc; int srcbit; _BS_size_t length; */ _BS_copy (register _BS_word* pdst, int dstbit, register const _BS_word* psrc, int srcbit, _BS_size_t length) { #define COMBINE(dst, src) (src) #include "bitdo2.h" } galib247/examples/gnu/bitcount.c0100644003643600364360000000400610573535475016046 0ustar mwallmwall/* Copyright (C) 1994 Free Software Foundation This file is part of the GNU BitString Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this library; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. As a special exception, if you link this library with files compiled with a GNU compiler to produce an executable, this does not cause the resulting executable to be covered by the GNU General Public License. This exception does not however invalidate any other reasons why the executable file might be covered by the GNU General Public License. */ /* Written by Per Bothner (bothner@cygnus.com) */ #include "bitprims.h" /* bit_count[I] is number of '1' bits in I. */ static const unsigned char four_bit_count[16] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4}; #if !defined(inline) && !defined(__GNUC__) && !defined(__cplusplus) #define inline #endif static inline int /* _BS_count_word (word) register _BS_word word; */ _BS_count_word (register _BS_word word) { register int count = 0; while (word > 0) { count += four_bit_count[word & 15]; word >>= 4; } return count; } int /* _BS_count (ptr, offset, length) register const _BS_word *ptr; int offset; _BS_size_t length; */ _BS_count (register const _BS_word *ptr, int offset, _BS_size_t length) { register int count = 0; #undef DOIT #define DOIT(WORD, MASK) count += _BS_count_word ((WORD) & (MASK)); #include "bitdo1.h" return count; } galib247/examples/gnu/bitdo1.h0100644003643600364360000000126710573535475015414 0ustar mwallmwall#ifndef ONES #define ONES ((_BS_word)(~0L)) #endif register int nwords; register _BS_word mask; if (offset == 0) ; else if (offset + length >= _BS_BITS_PER_WORD) { mask = ONES _BS_RIGHT offset; DOIT(*ptr++, mask); length -= _BS_BITS_PER_WORD - offset; } else { mask = (ONES _BS_RIGHT (_BS_BITS_PER_WORD - length)) _BS_LEFT (_BS_BITS_PER_WORD - length - offset); DOIT(*ptr, mask); goto done; } nwords = _BS_INDEX(length); while (--nwords >= 0) { DOIT(*ptr++, ONES); } length = _BS_POS (length); if (length) { mask = ONES _BS_LEFT (_BS_BITS_PER_WORD - length); DOIT(*ptr, mask); } done: ; galib247/examples/gnu/bitdo2.h0100644003643600364360000001126710573535475015416 0ustar mwallmwall#ifndef ONES #define ONES ((_BS_word)(~0L)) #endif #ifndef DOIT_SOLID #ifdef DOIT #define DOIT_SOLID(dst, src) DOIT(dst, src, (_BS_word)(~0)) #else #define DOIT_SOLID(dst, src) (dst) = (COMBINE(dst, src)) #endif #endif #ifndef DOIT #define DOIT(dst, src, mask) \ (dst) = ((COMBINE(dst, src)) & (mask)) | ((dst) & ~(mask)) #endif _BS_word word0, mask; int shift0, shift1; if (length == 0) goto done; shift0 = srcbit - dstbit; /* First handle the case that only one destination word is touched. */ if (length + dstbit <= _BS_BITS_PER_WORD) { _BS_word mask = (ONES _BS_LEFT (_BS_BITS_PER_WORD - length)) _BS_RIGHT dstbit; _BS_word word0 = *psrc++; if (shift0 <= 0) /* dstbit >= srcbit */ { word0 = word0 _BS_RIGHT (-shift0); } else { word0 = word0 _BS_LEFT shift0; if (length + srcbit > _BS_BITS_PER_WORD) word0 = word0 | (*psrc _BS_RIGHT (_BS_BITS_PER_WORD - shift0)); } DOIT(*pdst, word0, mask); goto done; } /* Next optimize the case that the source and destination are aligned. */ if (shift0 == 0) { _BS_word mask; if (psrc > pdst) { if (srcbit) { mask = ONES _BS_RIGHT srcbit; DOIT(*pdst, *psrc, mask); pdst++; psrc++; length -= _BS_BITS_PER_WORD - srcbit; } for (; length >= _BS_BITS_PER_WORD; length -= _BS_BITS_PER_WORD) { DOIT_SOLID(*pdst, *psrc); pdst++; psrc++; } if (length) { mask = ONES _BS_LEFT (_BS_BITS_PER_WORD - length); DOIT(*pdst, *psrc, mask); } } else if (psrc < pdst) { _BS_size_t span = srcbit + length; pdst += span / (_BS_size_t)_BS_BITS_PER_WORD; psrc += span / (_BS_size_t)_BS_BITS_PER_WORD; span %= (_BS_size_t)_BS_BITS_PER_WORD; if (span) { mask = ONES _BS_LEFT (_BS_BITS_PER_WORD - span); DOIT(*pdst, *psrc, mask); length -= span; } pdst--; psrc--; for (; length >= _BS_BITS_PER_WORD; length -= _BS_BITS_PER_WORD) { DOIT_SOLID(*pdst, *psrc); pdst--; psrc--; } if (srcbit) { mask = ONES _BS_RIGHT srcbit; DOIT(*pdst, *psrc, mask); } } /* else if (psrc == pdst) --nothing to do--; */ goto done; } /* Now we assume shift!=0, and more than on destination word is changed. */ if (psrc >= pdst) /* Do the updates in forward direction. */ { _BS_word word0 = *psrc++; _BS_word mask = ONES _BS_RIGHT dstbit; if (shift0 > 0) { _BS_word word1 = *psrc++; shift1 = _BS_BITS_PER_WORD - shift0; DOIT(*pdst, (word0 _BS_LEFT shift0) | (word1 _BS_RIGHT shift1), mask); word0 = word1; } else /* dstbit > srcbit */ { shift1 = -shift0; shift0 += _BS_BITS_PER_WORD; DOIT(*pdst, word0 _BS_RIGHT shift1, mask); } pdst++; length -= _BS_BITS_PER_WORD - dstbit; for ( ; length >= _BS_BITS_PER_WORD; length -= _BS_BITS_PER_WORD) { register _BS_word word1 = *psrc++; DOIT_SOLID(*pdst, (word0 _BS_LEFT shift0) | (word1 _BS_RIGHT shift1)); pdst++; word0 = word1; } if (length > 0) { _BS_size_t mask = ONES _BS_LEFT (_BS_BITS_PER_WORD - length); word0 = word0 _BS_LEFT shift0; if (length > shift1) word0 = word0 | (*psrc _BS_RIGHT shift1) ; DOIT (*pdst, word0, mask); } } else /* Do the updates in backward direction. */ { _BS_word word0; /* Make (psrc, srcbit) and (pdst, dstbit) point to *last* bit. */ psrc += (srcbit + length - 1) / _BS_BITS_PER_WORD; srcbit = (srcbit + length - 1) % _BS_BITS_PER_WORD; pdst += (dstbit + length - 1) / _BS_BITS_PER_WORD; dstbit = (dstbit + length - 1) % _BS_BITS_PER_WORD; shift0 = srcbit - dstbit; word0 = *psrc--; mask = ONES _BS_LEFT (_BS_BITS_PER_WORD - 1 - dstbit); if (shift0 < 0) { _BS_word word1 = *psrc--; shift1 = -shift0; shift0 += _BS_BITS_PER_WORD; DOIT (*pdst, (word0 _BS_RIGHT shift1) | (word1 _BS_LEFT shift0), mask); word0 = word1; } else { shift1 = _BS_BITS_PER_WORD - shift0; DOIT(*pdst, word0 _BS_LEFT shift0, mask); } pdst--; length -= dstbit + 1; for ( ; length >= _BS_BITS_PER_WORD; length -= _BS_BITS_PER_WORD) { register _BS_word word1 = *psrc--; DOIT_SOLID(*pdst, (word0 _BS_RIGHT shift1) | (word1 _BS_LEFT shift0)); pdst--; word0 = word1; } if (length > 0) { _BS_size_t mask = ONES _BS_RIGHT (_BS_BITS_PER_WORD - length); word0 = word0 _BS_RIGHT shift1; if (length > shift0) word0 = word0 | (*psrc _BS_LEFT shift0) ; DOIT (*pdst, word0, mask); } } done: ; galib247/examples/gnu/bitinvert.c0100644003643600364360000000266610573535475016237 0ustar mwallmwall/* Copyright (C) 1994 Free Software Foundation This file is part of the GNU BitString Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this library; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. As a special exception, if you link this library with files compiled with a GNU compiler to produce an executable, this does not cause the resulting executable to be covered by the GNU General Public License. This exception does not however invalidate any other reasons why the executable file might be covered by the GNU General Public License. */ /* Written by Per Bothner (bothner@cygnus.com) */ #include "bitprims.h" void /* _BS_invert (ptr, offset, length) register _BS_word *ptr; int offset; _BS_size_t length; */ _BS_invert (register _BS_word *ptr,int offset,_BS_size_t length) { #undef DOIT #define DOIT(WORD, MASK) ((WORD) ^= (MASK)) #include "bitdo1.h" } galib247/examples/gnu/bitlcomp.c0100644003643600364360000000547710573535475016045 0ustar mwallmwall/* Copyright (C) 1994 Free Software Foundation This file is part of the GNU BitString Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this library; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. As a special exception, if you link this library with files compiled with a GNU compiler to produce an executable, this does not cause the resulting executable to be covered by the GNU General Public License. This exception does not however invalidate any other reasons why the executable file might be covered by the GNU General Public License. */ /* Written by Per Bothner (bothner@cygnus.com) */ #include "bitprims.h" #include /* Return -1, 0, 1 depending on whether (ptr0, len0) is lexicographically less than, equal, or greater than (ptr1, len1). Both bitstrings must be left-aligned. */ int /* _BS_lcompare_0 (ptr0, len0, ptr1, len1) register _BS_word *ptr0; _BS_size_t len0; register _BS_word *ptr1; _BS_size_t len1; */ _BS_lcompare_0 (register _BS_word *ptr0, _BS_size_t len0, register _BS_word *ptr1, _BS_size_t len1) { _BS_size_t nwords0 = len0 / _BS_BITS_PER_WORD; _BS_size_t nwords1 = len1 / _BS_BITS_PER_WORD; register _BS_word word0, word1, mask; _BS_size_t nwords = nwords0 > nwords1 ? nwords1 : nwords0; for (; nwords != 0; nwords--) { word0 = *ptr0++; word1 = *ptr1++; if (word0 != word1) { #if _BS_BIGENDIAN return (word0 < word1) ? -1 : 1; #else mask = 1; for (;;) { int bit0 = word0 & 1; int bit1 = word1 & 1; int diff = bit0 - bit1; if (diff) return diff; word0 >>= 1; word1 >>= 1; } #endif } } len0 -= nwords0 * _BS_BITS_PER_WORD; len1 -= nwords1 * _BS_BITS_PER_WORD; if (len0 == 0 || len1 == 0) return len0 == 0 - len1 == 0; len0 &= _BS_BITS_PER_WORD - 1; len1 &= _BS_BITS_PER_WORD - 1; word0 = *ptr0++ & ~((_BS_word)(~0) _BS_RIGHT len0); word1 = *ptr1++ & ~((_BS_word)(~0) _BS_RIGHT len1); if (word0 == word1) return len0 == len1 ? 0 : len0 < len1 ? -1 : 1; #if _BS_BIGENDIAN return (word0 < word1) ? -1 : 1; #else for (;;) { int bit0 = word0 & 1; int bit1 = word1 & 1; int diff = bit0 - bit1; if (diff) return diff; word0 >>= 1; word1 >>= 1; } #endif } galib247/examples/gnu/bitprims.h0100644003643600364360000000740310573535475016061 0ustar mwallmwall#ifndef _BS_PRIMS #define _BS_PRIMS /* A bitstring is an array of _BS_word. */ typedef unsigned long _BS_word; #define _BS_CHAR_BIT 8 #define _BS_BITS_PER_WORD (_BS_CHAR_BIT*sizeof(_BS_word)) #define _BS_WORDS_NEEDED(NBITS) ((NBITS+_BS_BITS_PER_WORD-1)/_BS_BITS_PER_WORD) /* For now, we number the bits in a _BS_word in little-endian order. Later, might use machine order. */ #ifdef CHILL_LIB #ifndef BITS_BIG_ENDIAN #include "config.h" #endif #define _BS_BIGENDIAN BITS_BIG_ENDIAN #else #define _BS_BIGENDIAN 0 #endif /* By "left" we mean where bit number 0 is. Hence, so left shift is << if we're numbering the bits in big-endian oder, and >> if we're numbering the bits in little-endian order. Currently, we always use little-endian order. Later, we might use machine-endian order. */ #if _BS_BIGENDIAN #define _BS_LEFT << #define _BS_RIGHT >> #else #define _BS_LEFT >> #define _BS_RIGHT << #endif #if _BS_BIGENDIAN #define _BS_BITMASK(BITNO) (1 << (_BS_BITS_PER_WORD - 1 - (BITNO))) #else #define _BS_BITMASK(BITNO) (1 << (BITNO)) #endif /* Given a PTR which may not be aligned on a _BS_word boundary, set NEW_PTR to point to (the beginning of) the corresponding _BS_word. Adjust the bit-offset OFFSET to compensate for the difference. */ #define _BS_ADJUST_ALIGNED(NEW_PTR, PTR, OFFSET) \ ( (NEW_PTR) = (_BS_word*)(((char*)(PTR)-(char*)0) & ~(sizeof(_BS_word)-1)), \ (OFFSET) += (char*)(PTR) - (char*)(NEW_PTR) ) /* Given a bit point (PTR, OFFSET) normalize it so that OFFSET < _BS_BITS_PER_WORD. */ #define _BS_NORMALIZE(PTR, OFFSET) \ { _BS_size_t __tmp_ind = _BS_INDEX (OFFSET); \ (PTR) += __tmp_ind; \ (OFFSET) -= __tmp_ind * _BS_BITS_PER_WORD; } #define _BS_INDEX(I) ((unsigned)(I) / _BS_BITS_PER_WORD) #define _BS_POS(I) ((I) & (_BS_BITS_PER_WORD -1 )) #ifndef _BS_size_t #if __GNUC__ > 1 #define _BS_size_t __SIZE_TYPE__ #else #define _BS_size_t unsigned long #endif #endif #ifndef __P #ifdef __STDC__ #define __P(protos) protos #else #define __P(protos) () #endif #endif /*!__P*/ #if !defined(__STDC__) && !defined(const) #define const #endif #if !defined(__STDC__) && !defined(void) #define void int #endif /* The 16 2-operand raster-ops: These match the correspodning GX codes in X11. */ enum _BS_alu { _BS_alu_clear = 0 /* 0 */, _BS_alu_and = 1 /* src & dst */, _BS_alu_andReverse = 2 /* src & ~dst */, _BS_alu_copy = 3 /* src */, _BS_alu_andInverted = 4 /* ~src & dst */, _BS_alu_noop = 5 /* dst */, _BS_alu_xor = 6 /* src ^ dst */, _BS_alu_or = 7 /* src | dst */, _BS_alu_nor = 8 /* ~src & ~dst */, _BS_alu_equiv = 9 /* ~(src ^ dst) */, _BS_alu_invert = 10 /* ~dst */, _BS_alu_orReverse = 11 /* src | ~dst */, _BS_alu_copyInverted = 12 /* ~src */, _BS_alu_orInverted = 13 /* ~src | dst */, _BS_alu_nand = 14 /* ~src | d~st */, _BS_alu_set = 15 /* ~src | dst */ }; #define _BS #define _BS #ifdef __cplusplus extern "C" { #endif extern void _BS_and __P((_BS_word*,int, const _BS_word*, int, _BS_size_t)); extern void _BS_blt __P((enum _BS_alu, _BS_word*,int, const _BS_word*,int, _BS_size_t)); extern void _BS_copy __P((_BS_word*,int, const _BS_word*,int, _BS_size_t)); #define _BS_copy_0(DS, SS, LENGTH) _BS_copy(DS, 0, SS, 0, LENGTH) extern int _BS_count __P((const _BS_word*, int, _BS_size_t)); extern int _BS_any __P((const _BS_word*, int, _BS_size_t)); extern void _BS_clear __P((_BS_word*, int, _BS_size_t)); extern void _BS_set __P((_BS_word*, int, _BS_size_t)); extern void _BS_invert __P((_BS_word*, int, _BS_size_t)); int _BS_lcompare_0 __P((_BS_word*, _BS_size_t, _BS_word*, _BS_size_t)); extern void _BS_xor __P((_BS_word*,int, const _BS_word*,int, _BS_size_t)); #ifdef __cplusplus } #endif #endif /* !_BS_PRIMS */ galib247/examples/gnu/bitset1.c0100644003643600364360000000266010573535475015576 0ustar mwallmwall/* Copyright (C) 1994 Free Software Foundation This file is part of the GNU BitString Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this library; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. As a special exception, if you link this library with files compiled with a GNU compiler to produce an executable, this does not cause the resulting executable to be covered by the GNU General Public License. This exception does not however invalidate any other reasons why the executable file might be covered by the GNU General Public License. */ /* Written by Per Bothner (bothner@cygnus.com) */ #include "bitprims.h" void /* _BS_set (ptr, offset, length) register _BS_word *ptr; int offset; _BS_size_t length; */ _BS_set (register _BS_word *ptr,int offset,_BS_size_t length) { #undef DOIT #define DOIT(WORD, MASK) ((WORD) |= (MASK)) #include "bitdo1.h" } galib247/examples/gnu/bitstr.C0100644003643600364360000001245210573535475015472 0ustar mwallmwall/* ---------------------------------------------------------------------------- bitstr.C mbwall 13sep95 Copyright 1995 Massachusetts Institute of Technology This code can be freely distributed and modified under the terms of the GNU public license. See the COPYING file for details. DESCRIPTION: Source file for the BitString genome (derived from the GNU BitString object). ---------------------------------------------------------------------------- */ #include #include "bitstr.h" // Set all the initial values to zero. We do NOT call the initialize method at // this point - initialization must be done explicitly by the user of the // genome (eg when the population is created or reset). If we called the // initializer routine here then we could end up with multiple initializations // and/or calls to dummy initializers (for example when the genome is // created with a dummy initializer and the initializer is assigned later on). BitStringGenome:: BitStringGenome(unsigned int l, GAGenome::Evaluator f, void * u) : GAGenome(UniformInitializer, UniformMutator, Comparator), BitString() { crossover(UniformCrossover); evaluator(f); ud=u; for(int i=0; i=0; i--) genome.gene(i, GARandomBit()); } // Randomly pick bits in the bit string then flip their values. We try to be // smart about the number of times we have to call any random functions. If // the requested likliehood is small enough (relative to the number of bits in // the genome) then we must do a weighted coin toss on each bit in the genome. // Otherwise, we just do the expected number of flips (note that this will not // guarantee the requested mutation rate, but it will come close when the // length of the bit string is long enough). int BitStringGenome::UniformMutator(GAGenome & c, float pmut) { BitStringGenome &genome=(BitStringGenome &)c; register int n, i; if(pmut <= 0.0) return(0); float nMut = pmut * (float)(genome.length()); if(nMut < 1.0){ // we have to do a flip test on each bit nMut = 0; for(i=genome.length()-1; i>=0; i--){ if(GAFlipCoin(pmut)){ genome.gene(i, genome.gene(i) ? 0 : 1); nMut++; } } } else{ // only flip the number of bits we need to flip for(n=1; n=0; i--) if(sis.gene(i) == bro.gene(i)) count += 1.0; return count / sis.length(); } // This is a an implementation of a uniform crossover for the binary string. // It assumes that the the genomes are all the same length. int BitStringGenome::UniformCrossover(const GAGenome& a, const GAGenome& b, GAGenome* c, GAGenome* d) { BitStringGenome& mom=(BitStringGenome &)a; BitStringGenome& dad=(BitStringGenome &)b; int n = 0; if(c && d){ BitStringGenome& sis=(BitStringGenome &)*c; BitStringGenome& bro=(BitStringGenome &)*d; for(int i=sis.length()-1; i>=0; i--){ if(GARandomBit()){ sis.gene(i, mom.gene(i)); bro.gene(i, dad.gene(i)); } else{ sis.gene(i, dad.gene(i)); bro.gene(i, mom.gene(i)); } } n = 2; } else { BitStringGenome& sis = (c ? (BitStringGenome&)*c : (BitStringGenome&)*d); for(int i=sis.length()-1; i>=0; i--) sis.gene(i, (GARandomBit() ? mom.gene(i) : dad.gene(i))); n = 1; } return n; } galib247/examples/gnu/bitstr.h0100644003643600364360000000507510573535475015542 0ustar mwallmwall/* ---------------------------------------------------------------------------- bitstr.h mbwall 13sep95 Copyright 1995 Massachusetts Institute of Technology This code can be freely distributed and modified under the terms of the GNU public license. See the COPYING file for details. DESCRIPTION: Header file for the bitstring example. This code uses the BitString object from the GNU class library for the derivation of a new class of genomes. Here we define the genome and all of the basic operators that it needs to function. ---------------------------------------------------------------------------- */ #ifndef _bitstr_h_ #define _bitstr_h_ #include #include "BitString.h" // This is the class definition for the BitString genome. It is derived from // the Genome class and the GNU BitString class. We define here only the // additional methods that we'll need in order to use it a genome in GAlib. // The identity definition is to take care of the polymorphic nature of // GAlib genomes. You can use any number above 200 when defining your own // genome type. Anything under 200 is reserved for use in GAlib internals. // I have defined a 'gene' method here as a convenience routine. It simply // calls the BitString's bit access member function to determine if a bit is // set or not. When you call 'gene' with a second argument, it sets the // specified bit in the bitstring. // Unlike the binary string genomes included in GAlib, this genome is not // resizable. class BitStringGenome : public GAGenome, public BitString { public: GADefineIdentity("BitStringGenome", 201); static void UniformInitializer(GAGenome&); static int UniformMutator(GAGenome&, float); static float Comparator(const GAGenome&, const GAGenome&); static int UniformCrossover(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*); public: BitStringGenome(unsigned int x, GAGenome::Evaluator f=0, void * u=0); BitStringGenome(const BitStringGenome& orig) { copy(orig); } BitStringGenome& operator=(const GAGenome& orig) { copy(orig); return *this; } virtual ~BitStringGenome() {} virtual GAGenome *clone(GAGenome::CloneMethod) const; virtual void copy(const GAGenome&); int write (ostream& os) const { printon(os); return os.fail() ? 1 : 0; } int equal(const GAGenome & c) const { BitStringGenome & b = (BitStringGenome&)c; return ((BitString&)*this == (BitString&)b ? 1 : 0); } int gene(unsigned int x) const { return test(x); } int gene(unsigned int x, int b) { _evaluated = gaFalse; assign(x,b); return test(x); } }; #endif galib247/examples/gnu/BitString.cc0100644003643600364360000010632510573535475016276 0ustar mwallmwall/* Copyright (C) 1988 Free Software Foundation written by Doug Lea (dl@rocky.oswego.edu) This file is part of the GNU C++ Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* BitString class implementation */ #ifdef __GNUG__ #pragma implementation #endif #include #include #include #include #include #include #include #include #undef OK void BitString::error(const char* msg) const { (*lib_error_handler)("BitString", msg); } // globals BitStrRep _nilBitStrRep = { 0, 1, {0} }; BitString _nil_BitString; #define MINBitStrRep_SIZE 8 #define MAXBitStrRep_SIZE ((1 << (sizeof(short)*CHAR_BIT - 1)) - 1) #ifndef MALLOC_MIN_OVERHEAD #define MALLOC_MIN_OVERHEAD 4 #endif #define ONES ((_BS_word)(~0L)) #define MAXBIT (((_BS_word)1) << (BITSTRBITS - 1)) /* * bit manipulation utilities */ // break things up into .s indices and positions inline static int BitStr_len(int l) { return (unsigned)(l) / BITSTRBITS + 1; } // mask out low bits static inline _BS_word lmask(int p) { return ONES _BS_RIGHT p; } // mask out high bits static inline _BS_word rmask(int p) { int s = BITSTRBITS - 1 - p; if (s <= 0) return ONES; else return ONES _BS_LEFT s; } // mask out unused bits in last word of rep inline static void check_last(BitStrRep* r) { int bit_len_mod = r->len & (BITSTRBITS - 1); if (bit_len_mod) r->s[r->len / BITSTRBITS] &= ONES _BS_LEFT (BITSTRBITS - bit_len_mod); } // merge bits from next word static inline _BS_word borrow_hi(const _BS_word a[], int ind, int maxind, int p) { if (p == 0) return a[ind]; else if (ind < maxind) return (a[ind] _BS_LEFT p) | (a[ind+1] _BS_RIGHT (BITSTRBITS - p)); else return (a[ind] _BS_LEFT p); } // merge bits from prev word static inline _BS_word borrow_lo(const _BS_word a[], int ind, int minind, int p) { _BS_word word = a[ind] _BS_RIGHT (BITSTRBITS - 1 - p); if (ind > minind) word |= (a[ind-1] _BS_LEFT (p + 1)); return word; } // same with bounds check (for masks shorter than patterns) static inline _BS_word safe_borrow_hi(const _BS_word a[], int ind, int maxind, int p) { if (ind > maxind) return 0; else if (p == 0) return a[ind]; else if (ind == maxind) return a[ind] _BS_LEFT p; else return (a[ind] _BS_LEFT p) | (a[ind+1] _BS_RIGHT (BITSTRBITS - p)); } // allocate a new rep; pad to near a power of two inline static BitStrRep* BSnew(int newlen) { unsigned int siz = sizeof(BitStrRep) + BitStr_len(newlen) * sizeof(_BS_word) + MALLOC_MIN_OVERHEAD; unsigned int allocsiz = MINBitStrRep_SIZE;; while (allocsiz < siz) allocsiz <<= 1; allocsiz -= MALLOC_MIN_OVERHEAD; if (allocsiz >= MAXBitStrRep_SIZE * sizeof(_BS_word)) (*lib_error_handler)("BitString", "Requested length out of range"); BitStrRep* rep = new (operator new (allocsiz)) BitStrRep; memset(rep, 0, allocsiz); rep->sz = (allocsiz - sizeof(BitStrRep) + sizeof(_BS_word)) / sizeof(_BS_word); return rep; } inline void copy_bits (_BS_word* pdst, _BS_size_t dstbit, const _BS_word* psrc, _BS_size_t srcbit, _BS_size_t length) { _BS_NORMALIZE (pdst, dstbit); _BS_NORMALIZE (psrc, srcbit); _BS_copy (pdst, dstbit, psrc, srcbit, length); } BitStrRep* BStr_alloc(BitStrRep* old, const _BS_word* src, int startpos, int endp, int newlen) { if (old == &_nilBitStrRep) old = 0; if (newlen < 0) newlen = 0; int news = BitStr_len(newlen); BitStrRep* rep; if (old == 0 || news > old->sz) rep = BSnew(newlen); else rep = old; rep->len = newlen; if (src != 0 && endp > 0 && (src != rep->s || startpos > 0)) copy_bits (rep->s, 0, src, startpos, endp - startpos); check_last(rep); if (old != rep && old != 0) delete old; return rep; } BitStrRep* BStr_resize(BitStrRep* old, int newlen) { BitStrRep* rep; if (newlen < 0) newlen = 0; int news = BitStr_len(newlen); if (old == 0 || old == &_nilBitStrRep) { rep = BSnew(newlen); } else if (news > old->sz) { rep = BSnew(newlen); memcpy(rep->s, old->s, BitStr_len(old->len) * sizeof(_BS_word)); delete old; } else rep = old; rep->len = newlen; check_last(rep); return rep; } BitStrRep* BStr_copy(BitStrRep* old, const BitStrRep* src) { BitStrRep* rep; if (old == src && old != &_nilBitStrRep) return old; if (old == &_nilBitStrRep) old = 0; if (src == &_nilBitStrRep) src = 0; if (src == 0) { if (old == 0) rep = BSnew(0); else rep = old; rep->len = 0; } else { int newlen = src->len; int news = BitStr_len(newlen); if (old == 0 || news > old->sz) { rep = BSnew(newlen); if (old != 0) delete old; } else rep = old; memcpy(rep->s, src->s, news * sizeof(_BS_word)); rep->len = newlen; } check_last(rep); return rep; } int operator == (const BitString& x, const BitString& y) { return x.rep->len == y.rep->len && memcmp((void*)x.rep->s, (void*)y.rep->s, BitStr_len(x.rep->len) * sizeof(_BS_word)) == 0; } int operator <= (const BitString& x, const BitString& y) { unsigned int xl = x.rep->len; unsigned int yl = y.rep->len; if (xl > yl) return 0; const _BS_word* xs = x.rep->s; const _BS_word* topx = &(xs[BitStr_len(xl)]); const _BS_word* ys = y.rep->s; while (xs < topx) { _BS_word a = *xs++; _BS_word b = *ys++; if ((a | b) != b) return 0; } return 1; } int operator < (const BitString& x, const BitString& y) { unsigned short xl = x.rep->len; unsigned short yl = y.rep->len; if (xl > yl) return 0; const _BS_word* xs = x.rep->s; const _BS_word* ys = y.rep->s; const _BS_word* topx = &(xs[BitStr_len(xl)]); const _BS_word* topy = &(ys[BitStr_len(yl)]); int one_diff = 0; while (xs < topx) { _BS_word a = *xs++; _BS_word b = *ys++; _BS_word c = a | b; if (c != b) return 0; else if (c != a) one_diff = 1; } if (one_diff) return 1; else { while (ys < topy) if (*ys++ != 0) return 1; return 0; } } int lcompare(const BitString& x, const BitString& y) { return _BS_lcompare_0 (x.rep->s, x.rep->len, y.rep->s, y.rep->len); } int BitString::count(unsigned int b) const { int count = _BS_count (rep->s, 0, rep->len); if (!b) count = rep->len - count; return count; } BitStrRep* cmpl(const BitStrRep* src, BitStrRep* r) { r = BStr_copy(r, src); _BS_word* rs = r->s; _BS_word* topr = &(rs[BitStr_len(r->len)]); while (rs < topr) { _BS_word cmp = ~(*rs); *rs++ = cmp; } check_last(r); return r; } BitStrRep* and(const BitStrRep* x, const BitStrRep* y, BitStrRep* r) { int xrsame = x == r; int yrsame = y == r; unsigned int xl = x->len; unsigned int yl = y->len; unsigned int rl = (xl <= yl)? xl : yl; r = BStr_resize(r, rl); _BS_word* rs = r->s; _BS_word* topr = &(rs[BitStr_len(rl)]); const _BS_word* xs = (xrsame)? rs : x->s; const _BS_word* ys = (yrsame)? rs : y->s; while (rs < topr) *rs++ = *xs++ & *ys++; check_last(r); return r; } BitStrRep* or(const BitStrRep* x, const BitStrRep* y, BitStrRep* r) { unsigned int xl = x->len; unsigned int yl = y->len; unsigned int rl = (xl >= yl)? xl : yl; int xrsame = x == r; int yrsame = y == r; r = BStr_resize(r, rl); _BS_word* rs = r->s; const _BS_word* xs = (xrsame)? rs : x->s; const _BS_word* topx = &(xs[BitStr_len(xl)]); const _BS_word* ys = (yrsame)? rs : y->s; const _BS_word* topy = &(ys[BitStr_len(yl)]); if (xl <= yl) { while (xs < topx) *rs++ = *xs++ | *ys++; if (rs != ys) while (ys < topy) *rs++ = *ys++; } else { while (ys < topy) *rs++ = *xs++ | *ys++; if (rs != xs) while (xs < topx) *rs++ = *xs++; } check_last(r); return r; } BitStrRep* xor(const BitStrRep* x, const BitStrRep* y, BitStrRep* r) { unsigned int xl = x->len; unsigned int yl = y->len; unsigned int rl = (xl >= yl)? xl : yl; int xrsame = x == r; int yrsame = y == r; r = BStr_resize(r, rl); _BS_word* rs = r->s; const _BS_word* xs = (xrsame)? rs : x->s; const _BS_word* topx = &(xs[BitStr_len(xl)]); const _BS_word* ys = (yrsame)? rs : y->s; const _BS_word* topy = &(ys[BitStr_len(yl)]); if (xl <= yl) { while (xs < topx) *rs++ = *xs++ ^ *ys++; if (rs != ys) while (ys < topy) *rs++ = *ys++; } else { while (ys < topy) *rs++ = *xs++ ^ *ys++; if (rs != xs) while (xs < topx) *rs++ = *xs++; } check_last(r); return r; } BitStrRep* diff(const BitStrRep* x, const BitStrRep* y, BitStrRep* r) { unsigned int xl = x->len; unsigned int yl = y->len; int xrsame = x == y; int yrsame = y == r; r = BStr_resize(r, xl); _BS_word* rs = r->s; const _BS_word* xs = (xrsame)? rs : x->s; const _BS_word* topx = &(xs[BitStr_len(xl)]); const _BS_word* ys = (yrsame)? rs : y->s; const _BS_word* topy = &(ys[BitStr_len(yl)]); if (xl <= yl) { while (xs < topx) *rs++ = *xs++ & ~(*ys++); } else { while (ys < topy) *rs++ = *xs++ & ~(*ys++); if (rs != xs) while (xs < topx) *rs++ = *xs++; } check_last(r); return r; } BitStrRep* cat(const BitStrRep* x, const BitStrRep* y, BitStrRep* r) { unsigned int xl = x->len; unsigned int yl = y->len; unsigned int rl = xl + yl; int xrsame = x == r; int yrsame = y == r; if (yrsame) { if (xrsame) { r = BStr_resize(r, rl); copy_bits (r->s, xl, r->s, 0, yl); } else { BitStrRep* tmp = BStr_copy(0, y); r = BStr_resize(r, rl); _BS_copy_0(r->s, x->s, xl); copy_bits (r->s, xl, tmp->s, 0, yl); delete tmp; } } else { r = BStr_resize(r, rl); if (!xrsame) _BS_copy_0(r->s, x->s, xl); copy_bits (r->s, xl, y->s, 0, yl); } check_last(r); return r; } BitStrRep* cat(const BitStrRep* x, unsigned int bit, BitStrRep* r) { unsigned int xl = x->len; int xrsame = x == r; r = BStr_resize(r, xl+1); if (!xrsame) _BS_copy_0(r->s, x->s, xl); if (bit) r->s[BitStr_index(xl)] |= _BS_BITMASK(BitStr_pos(xl)); else r->s[BitStr_index(xl)] &= ~(_BS_BITMASK(BitStr_pos(xl))); check_last(r); return r; } BitStrRep* lshift(const BitStrRep* x, int s, BitStrRep* r) { int xrsame = x == r; int xl = x->len; int rl = xl + s; if (s == 0) r = BStr_copy(r, x); else if (rl <= 0) { r = BStr_resize(r, 0); r->len = 0; r->s[0] = 0; } else if (s > 0) { r = BStr_resize(r, rl); const _BS_word* xs = (xrsame)? r->s : x->s; copy_bits (r->s, s, xs, 0, xl); _BS_clear (r->s, 0, s); } else if (xrsame) { r = BStr_resize(r, xl); r->len = rl; copy_bits (r->s, 0, r->s, -s, xl + s); } else { r = BStr_resize(r, rl); copy_bits (r->s, 0, x->s, -s, xl + s); } check_last(r); return r; } void BitString::set(int p) { if (p < 0) error("Illegal bit index"); if ((unsigned)(p) >= rep->len) rep = BStr_resize(rep, p + 1); rep->s[BitStr_index(p)] |= _BS_BITMASK(BitStr_pos(p)); } void BitString::assign(int p, unsigned int bit) { if (p < 0) error("Illegal bit index"); if ((unsigned)(p) >= rep->len) rep = BStr_resize(rep, p + 1); if (bit) rep->s[BitStr_index(p)] |= _BS_BITMASK(BitStr_pos(p)); else rep->s[BitStr_index(p)] &= ~(_BS_BITMASK(BitStr_pos(p))); } void BitString::clear(int p) { if (p < 0) error("Illegal bit index"); if ((unsigned)(p) >= rep->len) rep = BStr_resize(rep, p + 1); rep->s[BitStr_index(p)] &= ~(_BS_BITMASK(BitStr_pos(p))); } void BitString::clear() { if (rep == &_nilBitStrRep) return; _BS_clear (rep->s, 0, rep->len); } void BitString::set() { if (rep == &_nilBitStrRep) return; _BS_word* s = rep->s; _BS_word* tops = &(s[BitStr_len(rep->len)]); while (s < tops) *s++ = ONES; check_last(rep); } void BitString::invert(int p) { if (p < 0) error("Illegal bit index"); if ((unsigned)(p) >= rep->len) rep = BStr_resize(rep, p + 1); rep->s[BitStr_index(p)] ^= _BS_BITMASK(BitStr_pos(p)); } void BitString::set(int from, int to) { if (from < 0 || from > to) error("Illegal bit index"); if ((unsigned)(to) >= rep->len) rep = BStr_resize(rep, to+1); _BS_size_t len = to - from + 1; _BS_word* xs = rep->s; _BS_NORMALIZE (xs, from); _BS_invert (xs, from, len); } void BitString::clear(int from, int to) { if (from < 0 || from > to) error("Illegal bit index"); if ((unsigned)(to) >= rep->len) rep = BStr_resize(rep, to+1); _BS_size_t len = to - from + 1; _BS_word* xs = rep->s; _BS_NORMALIZE (xs, from); _BS_clear (xs, from, len); } void BitString::invert(int from, int to) { if (from < 0 || from > to) error("Illegal bit index"); if ((unsigned)(to) >= rep->len) rep = BStr_resize(rep, to+1); _BS_size_t len = to - from + 1; _BS_word* xs = rep->s; _BS_NORMALIZE (xs, from); _BS_invert (xs, from, len); } int BitString::test(int from, int to) const { if (from < 0 || from > to || (unsigned)(from) >= rep->len) return 0; _BS_size_t len = to - from + 1; _BS_word* xs = rep->s; _BS_NORMALIZE (xs, from); return _BS_any (xs, from, len); } int BitString::next(int p, unsigned int b) const { if ((unsigned)(++p) >= rep->len) return -1; int ind = BitStr_index(p); int pos = BitStr_pos(p); int l = BitStr_len(rep->len); int j = ind; const _BS_word* s = rep->s; _BS_word a = s[j] >> pos; int i = pos; if (b != 0) { for (; i < BITSTRBITS && a != 0; ++i) { if (a & 1) return j * BITSTRBITS + i; a >>= 1; } for (++j; j < l; ++j) { a = s[j]; for (i = 0; i < BITSTRBITS && a != 0; ++i) { if (a & 1) return j * BITSTRBITS + i; a >>= 1; } } return -1; } else { int last = BitStr_pos(rep->len); if (j == l - 1) { for (; i < last; ++i) { if ((a & 1) == 0) return j * BITSTRBITS + i; a >>= 1; } return -1; } for (; i < BITSTRBITS; ++i) { if ((a & 1) == 0) return j * BITSTRBITS + i; a >>= 1; } for (++j; j < l - 1; ++j) { a = s[j]; if (a != ONES) { for (i = 0; i < BITSTRBITS; ++i) { if ((a & 1) == 0) return j * BITSTRBITS + i; a >>= 1; } } } a = s[j]; for (i = 0; i < last; ++i) { if ((a & 1) == 0) return j * BITSTRBITS + i; a >>= 1; } return -1; } } int BitString::prev(int p, unsigned int b) const { if (--p < 0) return -1; int ind = BitStr_index(p); int pos = BitStr_pos(p); const _BS_word* s = rep->s; if ((unsigned)(p) >= rep->len) { ind = BitStr_index(rep->len - 1); pos = BitStr_pos(rep->len - 1); } int j = ind; _BS_word a = s[j]; int i = pos; _BS_word maxbit = ((_BS_word)1) << pos; if (b != 0) { for (; i >= 0 && a != 0; --i) { if (a & maxbit) return j * BITSTRBITS + i; a <<= 1; } maxbit = ((_BS_word)1) << (BITSTRBITS - 1); for (--j; j >= 0; --j) { a = s[j]; for (i = BITSTRBITS - 1; i >= 0 && a != 0; --i) { if (a & maxbit) return j * BITSTRBITS + i; a <<= 1; } } return -1; } else { if (a != ONES) { for (; i >= 0; --i) { if ((a & maxbit) == 0) return j * BITSTRBITS + i; a <<= 1; } } maxbit = ((_BS_word)1) << (BITSTRBITS - 1); for (--j; j >= 0; --j) { a = s[j]; if (a != ONES) { for (i = BITSTRBITS - 1; i >= 0; --i) { if ((a & maxbit) == 0) return j * BITSTRBITS + i; a <<= 1; } } } return -1; } } int BitString::search(int startx, int lengthx, const _BS_word* ys, int starty, int lengthy) const { const _BS_word* xs = rep->s; int ylen = lengthy - starty; int righty = lengthy - 1; int rev = startx < 0; if (rev) { int leftx = 0; int rightx = lengthx + startx; startx = rightx - ylen + 1; if (ylen == 0) return startx; if (starty < 0 || righty < 0 || startx < 0 || startx >= lengthx) return -1; int xind = BitStr_index(startx); int xpos = BitStr_pos(startx); int yind = BitStr_index(starty); int ypos = BitStr_pos(starty); int rightxind = BitStr_index(rightx); _BS_word x = borrow_hi(xs, xind, rightxind, xpos); int rightyind = BitStr_index(righty); int rightypos = BitStr_pos(righty); _BS_word y = borrow_hi(ys, yind, rightyind, ypos); _BS_word ymask; if (yind == rightyind) ymask = rmask(rightypos); else if (yind+1 == rightyind) ymask = rmask(BITSTRBITS - ypos + rightypos + 1); else ymask = ONES; int p = startx; for (;;) { if ((x & ymask) == y) { int xi = xind; int yi = yind; for (;;) { if (++yi > rightyind || ++xi > rightxind) return p; _BS_word tx = borrow_hi(xs, xi, rightxind, xpos); _BS_word ty = borrow_hi(ys, yi, rightyind, ypos); if (yi == rightyind) tx &= rmask(rightypos); else if (yi+1 == rightyind) tx &= rmask(BITSTRBITS - ypos + rightypos + 1); if (tx != ty) break; } } if (--p < leftx) return -1; if (--xpos < 0) { xpos = BITSTRBITS - 1; --xind; } x = borrow_hi(xs, xind, rightxind, xpos); } } else { int rightx = lengthx - 1; if (ylen == 0) return startx; if (starty < 0 || righty < 0 || startx < 0 || startx >= lengthx) return -1; int xind = BitStr_index(startx); int xpos = BitStr_pos(startx); int yind = BitStr_index(starty); int ypos = BitStr_pos(starty); int rightxind = BitStr_index(rightx); _BS_word x = borrow_hi(xs, xind, rightxind, xpos); _BS_word nextx = (xind >= rightxind) ? 0 : (xs[xind+1] >> xpos); int rightyind = BitStr_index(righty); int rightypos = BitStr_pos(righty); _BS_word y = borrow_hi(ys, yind, rightyind, ypos); _BS_word ymask; if (yind == rightyind) ymask = rmask(rightypos); else if (yind+1 == rightyind) ymask = rmask(BITSTRBITS - ypos + rightypos + 1); else ymask = ONES; int p = startx; for (;;) { if ((x & ymask) == y) { int xi = xind; int yi = yind; for (;;) { if (++yi > rightyind || ++xi > rightxind) return p; _BS_word tx = borrow_hi(xs, xi, rightxind, xpos); _BS_word ty = borrow_hi(ys, yi, rightyind, ypos); if (yi == rightyind) tx &= rmask(rightypos); else if (yi+1 == rightyind) tx &= rmask(BITSTRBITS - ypos + rightypos + 1); if (tx != ty) break; } } if (++p > rightx) return -1; if (++xpos == BITSTRBITS) { xpos = 0; x = xs[++xind]; nextx = (xind >= rightxind) ? 0 : xs[xind+1]; } else { x >>= 1; if (nextx & 1) x |= MAXBIT; nextx >>= 1; } } } } int BitPattern::search(const _BS_word* xs, int startx, int lengthx) const { const _BS_word* ys = pattern.rep->s; const _BS_word* ms = mask.rep->s; int righty = pattern.rep->len - 1; int rightm = mask.rep->len - 1; int rev = startx < 0; if (rev) { int leftx = 0; int rightx = lengthx + startx; startx = rightx - righty; if (righty < 0) return startx; if (startx < 0 || startx >= lengthx) return -1; int xind = BitStr_index(startx); int xpos = BitStr_pos(startx); int rightxind = BitStr_index(rightx); int rightmind = BitStr_index(rightm); int rightyind = BitStr_index(righty); _BS_word x = safe_borrow_hi(xs, xind, rightxind, xpos); _BS_word m = safe_borrow_hi(ms, 0, rightmind, 0); _BS_word y = safe_borrow_hi(ys, 0, rightyind, 0) & m; int p = startx; for (;;) { if ((x & m) == y) { int xi = xind; int yi = 0; for (;;) { if (++yi > rightyind || ++xi > rightxind) return p; _BS_word tm = safe_borrow_hi(ms, yi, rightmind, 0); _BS_word ty = safe_borrow_hi(ys, yi, rightyind, 0); _BS_word tx = safe_borrow_hi(xs, xi, rightxind, xpos); if ((tx & tm) != (ty & tm)) break; } } if (--p < leftx) return -1; if (--xpos < 0) { xpos = BITSTRBITS - 1; --xind; } x = safe_borrow_hi(xs, xind, rightxind, xpos); } } else { int rightx = lengthx - 1; if (righty < 0) return startx; if (startx < 0 || startx >= lengthx) return -1; int xind = BitStr_index(startx); int xpos = BitStr_pos(startx); int rightxind = BitStr_index(rightx); int rightmind = BitStr_index(rightm); int rightyind = BitStr_index(righty); _BS_word x = safe_borrow_hi(xs, xind, rightxind, xpos); _BS_word m = safe_borrow_hi(ms, 0, rightmind, 0); _BS_word y = safe_borrow_hi(ys, 0, rightyind, 0) & m; _BS_word nextx = (xind >= rightxind) ? 0 : (xs[xind+1] >> xpos); int p = startx; for (;;) { if ((x & m) == y) { int xi = xind; int yi = 0; for (;;) { if (++yi > rightyind || ++xi > rightxind) return p; _BS_word tm = safe_borrow_hi(ms, yi, rightmind, 0); _BS_word ty = safe_borrow_hi(ys, yi, rightyind, 0); _BS_word tx = safe_borrow_hi(xs, xi, rightxind, xpos); if ((tx & tm) != (ty & tm)) break; } } if (++p > rightx) return -1; if (++xpos == BITSTRBITS) { xpos = 0; x = xs[++xind]; nextx = (xind >= rightxind) ? 0 : xs[xind+1]; } else { x >>= 1; if (nextx & 1) x |= MAXBIT; nextx >>= 1; } } } } int BitString::match(int startx, int lengthx, int exact, const _BS_word* ys, int starty, int yl) const { const _BS_word* xs = rep->s; int ylen = yl - starty; int righty = yl - 1; int rightx; int rev = startx < 0; if (rev) { rightx = lengthx + startx; startx = rightx - ylen + 1; if (exact && startx != 0) return 0; } else { rightx = lengthx - 1; if (exact && rightx - startx != righty) return 0; } if (ylen == 0) return 1; if (righty < 0 || startx < 0 || startx >= lengthx) return 0; int xi = BitStr_index(startx); int xpos = BitStr_pos(startx); int yi = BitStr_index(starty); int ypos = BitStr_pos(starty); int rightxind = BitStr_index(rightx); int rightyind = BitStr_index(righty); int rightypos = BitStr_pos(righty); for (;;) { _BS_word x = borrow_hi(xs, xi, rightxind, xpos); _BS_word y = borrow_hi(ys, yi, rightyind, ypos); if (yi == rightyind) x &= rmask(rightypos); else if (yi+1 == rightyind) x &= rmask(BITSTRBITS - ypos + rightypos + 1); if (x != y) return 0; else if (++yi > rightyind || ++xi > rightxind) return 1; } } int BitPattern::match(const _BS_word* xs, int startx, int lengthx, int exact) const { const _BS_word* ys = pattern.rep->s; int righty = pattern.rep->len - 1; _BS_word* ms = mask.rep->s; int rightm = mask.rep->len - 1; int rightx; int rev = startx < 0; if (rev) { rightx = lengthx + startx; startx = rightx - righty; if (exact && startx != 0) return 0; } else { rightx = lengthx - 1; if (exact && rightx - startx != righty) return 0; } if (righty < 0) return 1; if (startx < 0 || startx >= lengthx) return 0; int xind = BitStr_index(startx); int xpos = BitStr_pos(startx); int yind = 0; int rightxind = BitStr_index(rightx); int rightyind = BitStr_index(righty); int rightmind = BitStr_index(rightm); for(;;) { _BS_word m = safe_borrow_hi(ms, yind, rightmind, 0); _BS_word x = safe_borrow_hi(xs, xind, rightxind, xpos) & m; _BS_word y = safe_borrow_hi(ys, yind, rightyind, 0) & m; if (x != y) return 0; else if (++yind > rightyind || ++xind > rightxind) return 1; } } BitSubString& BitSubString::operator = (const BitString& y) { if (&S == &_nil_BitString) return *this; BitStrRep* targ = S.rep; unsigned int ylen = y.rep->len; int sl = targ->len - len + ylen; if (y.rep == targ || ylen > len) { BitStrRep* oldtarg = targ; targ = BStr_alloc(0, 0, 0, 0, sl); _BS_copy (targ->s, 0, oldtarg->s, 0, pos); copy_bits (targ->s, pos, y.rep->s, 0, ylen); copy_bits (targ->s, pos + ylen, oldtarg->s, pos+len, oldtarg->len-pos-len); delete oldtarg; } else if (len == ylen) copy_bits (targ->s, pos, y.rep->s, 0, len); else if (ylen < len) { copy_bits (targ->s, pos, y.rep->s, 0, ylen); copy_bits (targ->s, pos + ylen, targ->s, pos + len, targ->len - pos - len); targ->len = sl; } check_last(targ); S.rep = targ; return *this; } BitSubString& BitSubString::operator = (const BitSubString& y) { if (&S == &_nil_BitString) return *this; BitStrRep* targ = S.rep; if (len == 0 || pos >= targ->len) return *this; int sl = targ->len - len + y.len; if (y.S.rep == targ || y.len > len) { BitStrRep* oldtarg = targ; targ = BStr_alloc(0, 0, 0, 0, sl); _BS_copy_0(targ->s, oldtarg->s, pos); copy_bits (targ->s, pos, y.S.rep->s, y.pos, y.len); copy_bits (targ->s, pos + y.len, oldtarg->s, pos+len, oldtarg->len-pos-len); delete oldtarg; } else if (len == y.len) copy_bits (targ->s, pos, y.S.rep->s, y.pos, y.len); else if (y.len < len) { copy_bits (targ->s, pos, y.S.rep->s, y.pos, y.len); copy_bits (targ->s, pos + y.len, targ->s, pos + len, targ->len - pos - len); targ->len = sl; } check_last(targ); S.rep = targ; return *this; } BitSubString BitString::at(int first, int len) { return _substr(first, len); } BitSubString BitString::before(int pos) { return _substr(0, pos); } BitSubString BitString::after(int pos) { return _substr(pos + 1, rep->len - (pos + 1)); } BitSubString BitString::at(const BitString& y, int startpos) { int first = search(startpos, rep->len, y.rep->s, 0, y.rep->len); return _substr(first, y.rep->len); } BitSubString BitString::before(const BitString& y, int startpos) { int last = search(startpos, rep->len, y.rep->s, 0, y.rep->len); return _substr(0, last); } BitSubString BitString::after(const BitString& y, int startpos) { int first = search(startpos, rep->len, y.rep->s, 0, y.rep->len); if (first >= 0) first += y.rep->len; return _substr(first, rep->len - first); } BitSubString BitString::at(const BitSubString& y, int startpos) { int first = search(startpos, rep->len, y.S.rep->s, y.pos, y.len); return _substr(first, y.len); } BitSubString BitString::before(const BitSubString& y, int startpos) { int last = search(startpos, rep->len, y.S.rep->s, y.pos, y.len); return _substr(0, last); } BitSubString BitString::after(const BitSubString& y, int startpos) { int first = search(startpos, rep->len, y.S.rep->s, y.pos, y.len); if (first >= 0) first += y.len; return _substr(first, rep->len - first); } BitSubString BitString::at(const BitPattern& r, int startpos) { int first = r.search(rep->s, startpos, rep->len); return _substr(first, r.pattern.rep->len); } BitSubString BitString::before(const BitPattern& r, int startpos) { int first = r.search(rep->s, startpos, rep->len); return _substr(0, first); } BitSubString BitString::after(const BitPattern& r, int startpos) { int first = r.search(rep->s, startpos, rep->len); if (first >= 0) first += r.pattern.rep->len; return _substr(first, rep->len - first); } #if defined(__GNUG__) && !defined(_G_NO_NRV) #define RETURN(r) return #define RETURNS(r) return r; #define RETURN_OBJECT(TYPE, NAME) /* nothing */ #define USE_UNSIGNED 1 /* probably correct */ #else /* _G_NO_NRV */ #define RETURN(r) return r #define RETURNS(r) /* nothing */ #define RETURN_OBJECT(TYPE, NAME) TYPE NAME; #define USE_UNSIGNED 0 /* probably old bug */ #endif BitString common_prefix (const BitString& x, const BitString& y, int startpos) RETURNS(r) { RETURN_OBJECT(BitString, r); unsigned int xl = x.rep->len; unsigned int yl = y.rep->len; unsigned int startx, starty; if (startpos < 0) { startx = xl + startpos; starty = yl + startpos; } else startx = starty = startpos; if (startx >= xl || starty >= yl) RETURN(r); const _BS_word* xs = &(x.rep->s[BitStr_index(startx)]); _BS_word a = *xs++; unsigned int xp = startx; const _BS_word* ys = &(y.rep->s[BitStr_index(starty)]); _BS_word b = *ys++; unsigned int yp = starty; for(; xp < xl && yp < yl; ++xp, ++yp) { _BS_word xbit = ((_BS_word)1) << (BitStr_pos(xp)); _BS_word ybit = ((_BS_word)1) << (BitStr_pos(yp)); if (((a & xbit) == 0) != ((b & ybit) == 0)) break; if (xbit == MAXBIT) a = *xs++; if (ybit == MAXBIT) b = *ys++; } r.rep = BStr_alloc(0, x.rep->s, startx, xp, xp - startx); RETURN(r); } BitString common_suffix (const BitString& x, const BitString& y, int startpos) RETURNS(r) { RETURN_OBJECT(BitString, r); unsigned int xl = x.rep->len; unsigned int yl = y.rep->len; unsigned int startx, starty; if (startpos < 0) { startx = xl + startpos; starty = yl + startpos; } else startx = starty = startpos; if (startx >= xl || starty >= yl) RETURN(r); const _BS_word* xs = &(x.rep->s[BitStr_index(startx)]); _BS_word a = *xs--; int xp = startx; const _BS_word* ys = &(y.rep->s[BitStr_index(starty)]); _BS_word b = *ys--; int yp = starty; for(; xp >= 0 && yp >= 0; --xp, --yp) { _BS_word xbit = ((_BS_word)1) << (BitStr_pos(xp)); _BS_word ybit = ((_BS_word)1) << (BitStr_pos(yp)); if (((a & xbit) == 0) != ((b & ybit) == 0)) break; if (xbit == 1) a = *xs--; if (ybit == 1) b = *ys--; } r.rep = BStr_alloc(0, x.rep->s, xp+1, startx+1, startx - xp); RETURN(r); } BitString reverse (const BitString& x) RETURNS(r) { RETURN_OBJECT(BitString, r); unsigned int yl = x.rep->len; BitStrRep* y = BStr_resize(0, yl); if (yl > 0) { const _BS_word* ls = x.rep->s; _BS_word lm = 1; _BS_word* rs = &(y->s[BitStr_index(yl - 1)]); _BS_word rm = ((_BS_word)1) << (BitStr_pos(yl - 1)); for (unsigned int l = 0; l < yl; ++l) { if (*ls & lm) *rs |= rm; if (lm == MAXBIT) { ++ls; lm = 1; } else lm <<= 1; if (rm == 1) { --rs; rm = MAXBIT; } else rm >>= 1; } } r.rep = y; RETURN(r); } BitString atoBitString (const char* s, char f, char t) RETURNS(res) { RETURN_OBJECT(BitString, res); int sl = strlen(s); BitStrRep* r = BStr_resize(0, sl); if (sl != 0) { unsigned int rl = 0; _BS_word* rs = r->s; _BS_word a = 0; _BS_word m = 1; unsigned int i = 0; for(;;) { char ch = s[i]; if (ch != t && ch != f) { *rs = a; break; } ++rl; if (ch == t) a |= m; if (++i == sl) { *rs = a; break; } else if (i % BITSTRBITS == 0) { *rs++ = a; a = 0; m = 1; } else m <<= 1; } r = BStr_resize(r, rl); } res.rep = r; RETURN(res); } BitPattern atoBitPattern (const char* s, char f,char t,char x) RETURNS(r) { RETURN_OBJECT(BitPattern, r); int sl = strlen(s); if (sl != 0) { unsigned int rl = 0; r.pattern.rep = BStr_resize(r.pattern.rep, sl); r.mask.rep = BStr_resize(r.mask.rep, sl); _BS_word* rs = r.pattern.rep->s; _BS_word* ms = r.mask.rep->s; _BS_word a = 0; _BS_word b = 0; _BS_word m = 1; unsigned int i = 0; for(;;) { char ch = s[i]; if (ch != t && ch != f && ch != x) { *rs = a; *ms = b; break; } ++rl; if (ch == t) { a |= m; b |= m; } else if (ch == f) { b |= m; } if (++i == sl) { *rs = a; *ms = b; break; } else if (i % BITSTRBITS == 0) { *rs++ = a; *ms++ = b; a = 0; b = 0; m = 1; } else m <<= 1; } r.pattern.rep = BStr_resize(r.pattern.rep, rl); r.mask.rep = BStr_resize(r.mask.rep, rl); } RETURN(r); } //extern AllocRing _libgxx_fmtq; void BitString::printon (ostream& os, char f, char t) const { unsigned int xl = rep->len; const _BS_word* ptr = rep->s; register streambuf *sb = os.rdbuf(); _BS_word a = 0; for (unsigned int i = 0; i < xl; ++i) { if (i % BITSTRBITS == 0) a = *ptr++; sb->sputc((a & 1)? t : f); a >>= 1; } } /* const char* BitStringtoa(const BitString& x, char f, char t) { int wrksiz = x.length() + 2; char* fmtbase = (char *) _libgxx_fmtq.alloc(wrksiz); ostrstream stream(fmtbase, wrksiz); x.printon(stream, f, t); stream << ends; return fmtbase; } */ ostream& operator << (ostream& s, const BitString& x) { if (s.opfx()) x.printon(s); return s; } /* const char* BitPatterntoa(const BitPattern& p, char f,char t,char x) { unsigned int pl = p.pattern.rep->len; unsigned int ml = p.mask.rep->len; unsigned int l = (pl <= ml)? pl : ml; int wrksiz = l + 2; char* fmtbase = (char *) _libgxx_fmtq.alloc(wrksiz); ostrstream stream(fmtbase, wrksiz); p.printon(stream, f, t, x); stream << ends; return fmtbase; } */ void BitPattern::printon(ostream& s, char f,char t,char x) const { unsigned int pl = pattern.rep->len; unsigned int ml = mask.rep->len; unsigned int l = (pl <= ml)? pl : ml; register streambuf *sb = s.rdbuf(); const _BS_word* ps = pattern.rep->s; const _BS_word* ms = mask.rep->s; _BS_word a = 0; _BS_word m = 0; for (unsigned int i = 0; i < l; ++i) { if (i % BITSTRBITS == 0) { a = *ps++; m = *ms++; } if (m & 1) sb->sputc((a & 1)? t : f); else sb->sputc(x); a >>= 1; m >>= 1; } } ostream& operator << (ostream& s, const BitPattern& x) { if (s.opfx()) x.printon(s); return s; } int BitString::OK() const { int v = rep != 0; // have a rep; v &= BitStr_len(rep->len) <= rep->sz; // within allocated size if (!v) error("invariant failure"); return v; } int BitSubString::OK() const { int v = S.OK(); // valid BitString v &= pos + len <= S.rep->len; // within bounds of targ if (!v) S.error("BitSubString invariant failure"); return v; } int BitPattern::OK() const { int v = pattern.OK() && mask.OK(); if (!v) pattern.error("BitPattern invariant failure"); return v; } galib247/examples/gnu/BitString.h0100644003643600364360000004744410573535475016146 0ustar mwallmwall// This may look like C code, but it is really -*- C++ -*- /* Copyright (C) 1988 Free Software Foundation written by Doug Lea (dl@rocky.oswego.edu) This file is part of the GNU C++ Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _BitString_h #ifdef __GNUG__ #pragma interface #endif #define _BitString_h 1 #include #include #undef OK #include #define BITSTRBITS _BS_BITS_PER_WORD struct BitStrRep { unsigned int len; // length in bits unsigned short sz; // allocated slots _BS_word s[1]; // bits start here }; extern BitStrRep* BStr_alloc(BitStrRep*, const _BS_word*, int, int,int); extern BitStrRep* BStr_resize(BitStrRep*, int); extern BitStrRep* BStr_copy(BitStrRep*, const BitStrRep*); extern BitStrRep* cmpl(const BitStrRep*, BitStrRep*); extern BitStrRep* and(const BitStrRep*, const BitStrRep*, BitStrRep*); extern BitStrRep* or(const BitStrRep*, const BitStrRep*, BitStrRep*); extern BitStrRep* xor(const BitStrRep*, const BitStrRep*, BitStrRep*); extern BitStrRep* diff(const BitStrRep*, const BitStrRep*, BitStrRep*); extern BitStrRep* cat(const BitStrRep*, const BitStrRep*, BitStrRep*); extern BitStrRep* cat(const BitStrRep*, unsigned int, BitStrRep*); extern BitStrRep* lshift(const BitStrRep*, int, BitStrRep*); class BitString; class BitPattern; class BitStrBit { protected: BitString& src; unsigned int pos; public: BitStrBit(BitString& v, int p); BitStrBit(const BitStrBit& b); ~BitStrBit(); operator unsigned int() const; int operator = (unsigned int b); }; class BitSubString { friend class BitString; friend class BitPattern; protected: BitString& S; unsigned int pos; unsigned int len; BitSubString(BitString& x, int p, int l); BitSubString(const BitSubString& x); public: ~BitSubString(); BitSubString& operator = (const BitString&); BitSubString& operator = (const BitSubString&); int length() const; int empty() const; int OK() const; }; class BitString { friend class BitSubString; friend class BitPattern; protected: BitStrRep* rep; int search(int, int, const _BS_word*, int, int) const; int match(int, int, int, const _BS_word*,int,int) const; BitSubString _substr(int first, int l); public: // constructors BitString(); BitString(const BitString&); BitString(const BitSubString& y); ~BitString(); BitString& operator = (unsigned int bit); BitString& operator = (const BitString& y); BitString& operator = (const BitSubString& y); // equality & subset tests friend int operator == (const BitString&, const BitString&); friend int operator != (const BitString&, const BitString&); friend int operator < (const BitString&, const BitString&); friend int operator <= (const BitString&, const BitString&); friend int operator > (const BitString&, const BitString&); friend int operator >= (const BitString&, const BitString&); // procedural versions of operators friend void and(const BitString&, const BitString&, BitString&); friend void or(const BitString&, const BitString&, BitString&); friend void xor(const BitString&, const BitString&, BitString&); friend void diff(const BitString&, const BitString&, BitString&); friend void cat(const BitString&, const BitString&, BitString&); friend void cat(const BitString&, unsigned int, BitString&); friend void lshift(const BitString&, int, BitString&); friend void rshift(const BitString&, int, BitString&); friend void complement(const BitString&, BitString&); friend int lcompare(const BitString&, const BitString&); // assignment-based operators // (constuctive versions decalred inline below BitString& operator |= (const BitString&); BitString& operator &= (const BitString&); BitString& operator -= (const BitString&); BitString& operator ^= (const BitString&); BitString& operator += (const BitString&); BitString& operator += (unsigned int b); BitString& operator <<=(int s); BitString& operator >>=(int s); void complement(); // individual bit manipulation void set(int pos); void set(int from, int to); void set(); void clear(int pos); void clear(int from, int to); void clear(); void invert(int pos); void invert(int from, int to); int test(int pos) const; int test(int from, int to) const; void assign(int p, unsigned int bit); // indexing BitStrBit operator [] (int pos); // iterators int first(unsigned int bit = 1) const; int last(unsigned int b = 1) const; int next(int pos, unsigned int b = 1) const; int prev(int pos, unsigned int b = 1) const; int previous(int pos, unsigned int b = 1) const { return prev(pos, b); } /* Obsolete synonym */ // searching & matching int index(unsigned int bit, int startpos = 0) const ; int index(const BitString&, int startpos = 0) const; int index(const BitSubString&, int startpos = 0) const; int index(const BitPattern&, int startpos = 0) const; int contains(const BitString&) const; int contains(const BitSubString&) const; int contains(const BitPattern&) const; int contains(const BitString&, int pos) const; int contains(const BitSubString&, int pos) const; int contains(const BitPattern&, int pos) const; int matches(const BitString&, int pos = 0) const; int matches(const BitSubString&, int pos = 0) const; int matches(const BitPattern&, int pos = 0) const; // BitSubString extraction BitSubString at(int pos, int len); BitSubString at(const BitString&, int startpos = 0); BitSubString at(const BitSubString&, int startpos = 0); BitSubString at(const BitPattern&, int startpos = 0); BitSubString before(int pos); BitSubString before(const BitString&, int startpos = 0); BitSubString before(const BitSubString&, int startpos = 0); BitSubString before(const BitPattern&, int startpos = 0); BitSubString after(int pos); BitSubString after(const BitString&, int startpos = 0); BitSubString after(const BitSubString&, int startpos = 0); BitSubString after(const BitPattern&, int startpos = 0); // other friends & utilities friend BitString common_prefix(const BitString&, const BitString&, int pos = 0); friend BitString common_suffix(const BitString&, const BitString&, int pos = -1); friend BitString reverse(const BitString&); void right_trim(unsigned int bit); void left_trim(unsigned int bit); // status int empty() const ; int count(unsigned int bit = 1) const; int length() const; // convertors & IO friend BitString atoBitString(const char* s, char f='0', char t='1'); // BitStringtoa is deprecated; do not use in new programs! // friend const char* BitStringtoa(const BitString&, char f='0', char t='1'); void printon(ostream&, char f='0', char t='1') const; friend BitString shorttoBitString(unsigned short); friend BitString longtoBitString(unsigned long); friend ostream& operator << (ostream& s, const BitString&); // misc void error(const char* msg) const; // indirect friends friend BitPattern atoBitPattern(const char* s, char f='0',char t='1',char x='X'); // friend const char* BitPatterntoa(const BitPattern& p, // char f='0',char t='1',char x='X'); int OK() const; }; class BitPattern { public: BitString pattern; BitString mask; BitPattern(); BitPattern(const BitPattern&); BitPattern(const BitString& p, const BitString& m); ~BitPattern(); friend const char* BitPatterntoa(const BitPattern& p, char f/*='0'*/,char t/*='1'*/,char x/*='X'*/); void printon(ostream&, char f='0',char t='1',char x='X') const; friend BitPattern atoBitPattern(const char* s, char f,char t, char x); friend ostream& operator << (ostream& s, const BitPattern&); int search(const _BS_word*, int, int) const; int match(const _BS_word* xs, int, int, int) const; int OK() const; }; BitString operator & (const BitString& x, const BitString& y); BitString operator | (const BitString& x, const BitString& y); BitString operator ^ (const BitString& x, const BitString& y); BitString operator << (const BitString& x, int y); BitString operator >> (const BitString& x, int y); BitString operator - (const BitString& x, const BitString& y); BitString operator + (const BitString& x, const BitString& y); BitString operator + (const BitString& x, unsigned int y); BitString operator ~ (const BitString& x); int operator != (const BitString& x, const BitString& y); int operator>(const BitString& x, const BitString& y); int operator>=(const BitString& x, const BitString& y); extern BitStrRep _nilBitStrRep; extern BitString _nil_BitString; // primitive bit extraction // These must be inlined regardless of optimization. inline int BitStr_index(int l) { return (unsigned)(l) / BITSTRBITS; } inline int BitStr_pos(int l) { return l & (BITSTRBITS - 1); } // constructors & assignment inline BitString::BitString() :rep(&_nilBitStrRep) {} inline BitString::BitString(const BitString& x) :rep(BStr_copy(0, x.rep)) {} inline BitString::BitString(const BitSubString& y) :rep (BStr_alloc(0, y.S.rep->s, y.pos, y.pos+y.len, y.len)) {} inline BitString::~BitString() { if (rep != &_nilBitStrRep) delete rep; } inline BitString shorttoBitString(unsigned short w) { BitString r; _BS_word ww = w; #if _BS_BIGENDIAN abort(); #endif r.rep = BStr_alloc(0, &ww, 0, 8 * sizeof(short), 8 * sizeof(short)); return r; } inline BitString longtoBitString(unsigned long w) { BitString r; #if 1 _BS_word u = w; r.rep = BStr_alloc(0, &u, 0, BITSTRBITS, BITSTRBITS); #else unsigned short u[2]; u[0] = w & ((unsigned short)(~(0))); u[1] = w >> BITSTRBITS; r.rep = BStr_alloc(0, &u[0], 0, 2*BITSTRBITS, 2*BITSTRBITS); #endif return r; } inline BitString& BitString::operator = (const BitString& y) { rep = BStr_copy(rep, y.rep); return *this; } inline BitString& BitString::operator = (unsigned int b) { _BS_word bit = b; rep = BStr_alloc(rep, &bit, 0, 1, 1); return *this; } inline BitString& BitString::operator=(const BitSubString& y) { rep = BStr_alloc(rep, y.S.rep->s, y.pos, y.pos+y.len, y.len); return *this; } inline BitSubString::BitSubString(const BitSubString& x) :S(x.S), pos(x.pos), len(x.len) {} inline BitSubString::BitSubString(BitString& x, int p, int l) : S(x), pos(p), len(l) {} inline BitSubString::~BitSubString() {} inline BitPattern::BitPattern(const BitString& p, const BitString& m) :pattern(p), mask(m) {} inline BitPattern::BitPattern(const BitPattern& b) :pattern(b.pattern), mask(b.mask) {} inline BitPattern::BitPattern() {} inline BitPattern::~BitPattern() {} // procedural versions of operators inline void and(const BitString& x, const BitString& y, BitString& r) { r.rep = and(x.rep, y.rep, r.rep); } inline void or(const BitString& x, const BitString& y, BitString& r) { r.rep = or(x.rep, y.rep, r.rep); } inline void xor(const BitString& x, const BitString& y, BitString& r) { r.rep = xor(x.rep, y.rep, r.rep); } inline void diff(const BitString& x, const BitString& y, BitString& r) { r.rep = diff(x.rep, y.rep, r.rep); } inline void cat(const BitString& x, const BitString& y, BitString& r) { r.rep = cat(x.rep, y.rep, r.rep); } inline void cat(const BitString& x, unsigned int y, BitString& r) { r.rep = cat(x.rep, y, r.rep); } inline void rshift(const BitString& x, int y, BitString& r) { r.rep = lshift(x.rep, -y, r.rep); } inline void lshift(const BitString& x, int y, BitString& r) { r.rep = lshift(x.rep, y, r.rep); } inline void complement(const BitString& x, BitString& r) { r.rep = cmpl(x.rep, r.rep); } // operators inline BitString& BitString::operator &= (const BitString& y) { and(*this, y, *this); return *this; } inline BitString& BitString::operator |= (const BitString& y) { or(*this, y, *this); return *this; } inline BitString& BitString::operator ^= (const BitString& y) { xor(*this, y, *this); return *this; } inline BitString& BitString::operator <<= (int y) { lshift(*this, y, *this); return *this; } inline BitString& BitString::operator >>= (int y) { rshift(*this, y, *this); return *this; } inline BitString& BitString::operator -= (const BitString& y) { diff(*this, y, *this); return *this; } inline BitString& BitString::operator += (const BitString& y) { cat(*this, y, *this); return *this; } inline BitString& BitString::operator += (unsigned int y) { cat(*this, y, *this); return *this; } inline void BitString::complement() { ::complement(*this, *this); } #if defined(__GNUG__) && !defined(_G_NO_NRV) inline BitString operator & (const BitString& x, const BitString& y) return r { and(x, y, r); } inline BitString operator | (const BitString& x, const BitString& y) return r { or(x, y, r); } inline BitString operator ^ (const BitString& x, const BitString& y) return r { xor(x, y, r); } inline BitString operator << (const BitString& x, int y) return r { lshift(x, y, r); } inline BitString operator >> (const BitString& x, int y) return r { rshift(x, y, r); } inline BitString operator - (const BitString& x, const BitString& y) return r { diff(x, y, r); } inline BitString operator + (const BitString& x, const BitString& y) return r { cat(x, y, r); } inline BitString operator + (const BitString& x, unsigned int y) return r { cat(x, y, r); } inline BitString operator ~ (const BitString& x) return r { complement(x, r); } #else /* NO_NRV */ inline BitString operator & (const BitString& x, const BitString& y) { BitString r; and(x, y, r); return r; } inline BitString operator | (const BitString& x, const BitString& y) { BitString r; or(x, y, r); return r; } inline BitString operator ^ (const BitString& x, const BitString& y) { BitString r; xor(x, y, r); return r; } inline BitString operator << (const BitString& x, int y) { BitString r; lshift(x, y, r); return r; } inline BitString operator >> (const BitString& x, int y) { BitString r; rshift(x, y, r); return r; } inline BitString operator - (const BitString& x, const BitString& y) { BitString r; diff(x, y, r); return r; } inline BitString operator + (const BitString& x, const BitString& y) { BitString r; cat(x, y, r); return r; } inline BitString operator + (const BitString& x, unsigned int y) { BitString r; cat(x, y, r); return r; } inline BitString operator ~ (const BitString& x) { BitString r; complement(x, r); return r; } #endif // status, matching inline int BitString::length() const { return rep->len; } inline int BitString::empty() const { return rep->len == 0; } inline int BitString::index(const BitString& y, int startpos) const { return search(startpos, rep->len, y.rep->s, 0, y.rep->len); } inline int BitString::index(const BitSubString& y, int startpos) const { return search(startpos, rep->len, y.S.rep->s, y.pos, y.pos+y.len); } inline int BitString::contains(const BitString& y) const { return search(0, rep->len, y.rep->s, 0, y.rep->len) >= 0; } inline int BitString::contains(const BitSubString& y) const { return search(0, rep->len, y.S.rep->s, y.pos, y.pos+y.len) >= 0; } inline int BitString::contains(const BitString& y, int p) const { return match(p, rep->len, 0, y.rep->s, 0, y.rep->len); } inline int BitString::matches(const BitString& y, int p) const { return match(p, rep->len, 1, y.rep->s, 0, y.rep->len); } inline int BitString::contains(const BitSubString& y, int p) const { return match(p, rep->len, 0, y.S.rep->s, y.pos, y.pos+y.len); } inline int BitString::matches(const BitSubString& y, int p) const { return match(p, rep->len, 1, y.S.rep->s, y.pos, y.pos+y.len); } inline int BitString::contains(const BitPattern& r) const { return r.search(rep->s, 0, rep->len) >= 0; } inline int BitString::contains(const BitPattern& r, int p) const { return r.match(rep->s, p, rep->len, 0); } inline int BitString::matches(const BitPattern& r, int p) const { return r.match(rep->s, p, rep->len, 1); } inline int BitString::index(const BitPattern& r, int startpos) const { return r.search(rep->s, startpos, rep->len); } inline int BitSubString::length() const { return len; } inline int BitSubString::empty() const { return len == 0; } inline int operator != (const BitString& x, const BitString& y) { return !(x == y); } inline int operator>(const BitString& x, const BitString& y) { return y < x; } inline int operator>=(const BitString& x, const BitString& y) { return y <= x; } inline int BitString::first(unsigned int b) const { return next(-1, b); } inline int BitString::last(unsigned int b) const { return prev(rep->len, b); } inline int BitString::index(unsigned int bit, int startpos) const { if (startpos >= 0) return next(startpos - 1, bit); else return prev(rep->len + startpos + 1, bit); } inline void BitString::right_trim(unsigned int b) { int nb = (b == 0)? 1 : 0; rep = BStr_resize(rep, prev(rep->len, nb) + 1); } inline void BitString::left_trim(unsigned int b) { int nb = (b == 0)? 1 : 0; int p = next(-1, nb); rep = BStr_alloc(rep, rep->s, p, rep->len, rep->len - p); } inline int BitString::test(int i) const { return ((unsigned)(i) >= rep->len)? 0 : ((rep->s[BitStr_index(i)] & (1 << (BitStr_pos(i)))) != 0); } // subscripting inline BitStrBit::BitStrBit(const BitStrBit& b) :src(b.src), pos(b.pos) {} inline BitStrBit::BitStrBit(BitString& v, int p) :src(v), pos(p) {} inline BitStrBit::~BitStrBit() {} inline BitStrBit::operator unsigned int() const { return src.test(pos); } inline int BitStrBit::operator = (unsigned int b) { src.assign(pos, b); return b; } inline BitStrBit BitString::operator [] (int i) { if ((unsigned)(i) >= rep->len) error("illegal bit index"); return BitStrBit(*this, i); } inline BitSubString BitString::_substr(int first, int l) { if (first < 0 || l <= 0 || (unsigned)(first + l) > rep->len) return BitSubString(_nil_BitString, 0, 0) ; else return BitSubString(*this, first, l); } #endif galib247/examples/gnu/bitxor.c0100644003643600364360000000323310573535475015527 0ustar mwallmwall/* Copyright (C) 1994 Free Software Foundation This file is part of the GNU BitString Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this library; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. As a special exception, if you link this library with files compiled with a GNU compiler to produce an executable, this does not cause the resulting executable to be covered by the GNU General Public License. This exception does not however invalidate any other reasons why the executable file might be covered by the GNU General Public License. */ /* Written by Per Bothner (bothner@cygnus.com). */ #include "bitprims.h" /* Copy LENGTH bits from (starting at SRCBIT) into pdst starting at DSTBIT. This will work even if psrc & pdst overlap. */ void /* _BS_xor (pdst, dstbit, psrc, srcbit, length) register _BS_word* pdst; int dstbit; register const _BS_word* psrc; int srcbit; _BS_size_t length; */ _BS_xor (register _BS_word* pdst, int dstbit, register const _BS_word* psrc, int srcbit, _BS_size_t length) { #define COMBINE(dst, src) (dst) ^ (src) #include "bitdo2.h" } galib247/examples/gnu/builtin.cc0100644003643600364360000000010310573535475016022 0ustar mwallmwall#ifdef __GNUG__ #pragma implementation #endif #include galib247/examples/gnu/builtin.h0100644003643600364360000000602510573535475015675 0ustar mwallmwall// This may look like C code, but it is really -*- C++ -*- /* Copyright (C) 1988, 1992 Free Software Foundation written by Doug Lea (dl@rocky.oswego.edu) This file is part of the GNU C++ Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* arithmetic, etc. functions on built in types */ #ifndef _builtin_h #ifdef __GNUG__ #pragma interface #endif #define _builtin_h 1 #include #include #include #ifdef __GNUG__ #define _VOLATILE_VOID volatile void #else #define _VOLATILE_VOID void #endif typedef void (*one_arg_error_handler_t)(const char*); typedef void (*two_arg_error_handler_t)(const char*, const char*); long gcd(long, long); long lg(unsigned long); double pow(double, long); long pow(long, long); extern "C" double start_timer(); extern "C" double return_elapsed_time(double last_time = 0.0); char* dtoa(double x, char cvt = 'g', int width = 0, int prec = 6); unsigned int hashpjw(const char*); unsigned int multiplicativehash(int); unsigned int foldhash(double); extern _VOLATILE_VOID default_one_arg_error_handler(const char*); extern _VOLATILE_VOID default_two_arg_error_handler(const char*, const char*); extern two_arg_error_handler_t lib_error_handler; extern two_arg_error_handler_t set_lib_error_handler(two_arg_error_handler_t f); #if !defined(IV) #if ! _G_MATH_H_INLINES /* hpux and SCO define this in math.h */ inline double abs(double arg) { return (arg < 0.0)? -arg : arg; } #endif inline float abs(float arg) { return (arg < 0.0)? -arg : arg; } inline short abs(short arg) { return (arg < 0)? -arg : arg; } inline long abs(long arg) { return (arg < 0)? -arg : arg; } inline int sign(long arg) { return (arg == 0) ? 0 : ( (arg > 0) ? 1 : -1 ); } inline int sign(double arg) { return (arg == 0.0) ? 0 : ( (arg > 0.0) ? 1 : -1 ); } inline long sqr(long arg) { return arg * arg; } #if ! _G_MATH_H_INLINES /* hpux and SCO define this in math.h */ inline double sqr(double arg) { return arg * arg; } #endif inline int even(long arg) { return !(arg & 1); } inline int odd(long arg) { return (arg & 1); } inline long lcm(long x, long y) { return x / gcd(x, y) * y; } inline void (setbit)(long& x, long b) { x |= (1 << b); } inline void clearbit(long& x, long b) { x &= ~(1 << b); } inline int testbit(long x, long b) { return ((x & (1 << b)) != 0); } #endif #endif galib247/examples/gnu/COPYING.LIB0100644003643600364360000006126110573535476015522 0ustar mwallmwall GNU LIBRARY GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the library GPL. It is numbered 2 because it goes with version 2 of the ordinary GPL.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Library General Public License, applies to some specially designated Free Software Foundation software, and to any other libraries whose authors decide to use it. You can use it for your libraries, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library, or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link a program with the library, you must provide complete object files to the recipients so that they can relink them with the library, after making changes to the library and recompiling it. And you must show them these terms so they know their rights. Our method of protecting your rights has two steps: (1) copyright the library, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the library. Also, for each distributor's protection, we want to make certain that everyone understands that there is no warranty for this free library. If the library is modified by someone else and passed on, we want its recipients to know that what they have is not the original version, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that companies distributing free software will individually obtain patent licenses, thus in effect transforming the program into proprietary software. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License, which was designed for utility programs. This license, the GNU Library General Public License, applies to certain designated libraries. This license is quite different from the ordinary one; be sure to read it in full, and don't assume that anything in it is the same as in the ordinary license. The reason we have a separate public license for some libraries is that they blur the distinction we usually make between modifying or adding to a program and simply using it. Linking a program with a library, without changing the library, is in some sense simply using the library, and is analogous to running a utility program or application program. However, in a textual and legal sense, the linked executable is a combined work, a derivative of the original library, and the ordinary General Public License treats it as such. Because of this blurred distinction, using the ordinary General Public License for libraries did not effectively promote software sharing, because most developers did not use the libraries. We concluded that weaker conditions might promote sharing better. However, unrestricted linking of non-free programs would deprive the users of those programs of all benefit from the free status of the libraries themselves. This Library General Public License is intended to permit developers of non-free programs to use free libraries, while preserving your freedom as a user of such programs to change the free libraries that are incorporated in them. (We have not seen how to achieve this as regards changes in header files, but we have achieved it as regards changes in the actual functions of the Library.) The hope is that this will lead to faster development of free libraries. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, while the latter only works together with the library. Note that it is possible for a library to be covered by the ordinary General Public License rather than by this special one. GNU LIBRARY GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Library General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also compile or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. c) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. d) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Library General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! galib247/examples/gnu/error.cc0100644003643600364360000000344010573535476015515 0ustar mwallmwall/* Copyright (C) 1990 Free Software Foundation written by Doug Lea (dl@rocky.oswego.edu) This file is part of the GNU C++ Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #ifdef __GNUG__ #pragma implementation #endif #include #ifdef __GNUC__ typedef _VOLATILE_VOID (*NoReturnFunc)(void); /* Cast abort to a _VOLATILE_VOID function, even if differs. This is to avoid a warning from g++ that a `volatile' function does return. */ #define ABORT() ((NoReturnFunc)abort)() #else #define ABORT() abort() #endif _VOLATILE_VOID default_one_arg_error_handler(const char* msg) { fputs("Error: ", stderr); fputs(msg, stderr); fputs("\n", stderr); ABORT(); } _VOLATILE_VOID default_two_arg_error_handler(const char* kind, const char* msg) { fputs(kind, stderr); fputs(" Error: ", stderr); fputs(msg, stderr); fputs("\n", stderr); ABORT(); } two_arg_error_handler_t lib_error_handler = default_two_arg_error_handler; two_arg_error_handler_t set_lib_error_handler(two_arg_error_handler_t f) { two_arg_error_handler_t old = lib_error_handler; lib_error_handler = f; return old; } galib247/examples/gnu/gnuex.C0100644003643600364360000000725610573535475015317 0ustar mwallmwall/* ---------------------------------------------------------------------------- gnuex.C mbwall 13sep95 Copyright 1995 Massachusetts Institute of Technology This code can be freely distributed and modified under the terms of the GNU public license. See the COPYING file for details. DESCRIPTION: This example illustrates the use of a custom data structure (in this case the BitString object from the GNU g++ class library) with GAlib. This example uses a steady-state GA to evolve a bit string with alternating 1s and 0s. It uses a uniform crossover and bitflip mutation, both of which are custom written for use with the GNU BitString object. You can specify which type of genome you would like to use - the GNU bit string or the binary string built in to GAlib (I did this for some simple speed comparisons to get an idea of how efficiently each was implemented). In my simple tests I found the GAlib binary string object to be a bit faster than the GNU bit string (but the gnu bit string is a much more robust, more compact, etc implementation). ---------------------------------------------------------------------------- */ #include #include #include // this is the include file for the ga library // When this is defined, use the GNU BitString otherwise we use the // GA1DBinaryString that is built in to GAlib. #define USE_GNU #ifdef USE_GNU #include "bitstr.h" // this header contains the genome we defined #define GENOME_TYPE BitStringGenome #else #define GENOME_TYPE GA1DBinaryStringGenome #endif float Objective(GAGenome &); int main() { cout << "This program tries to fill a bit string with\n"; cout << "alternating 1s and 0s using a steady-state GA,\n"; cout << "uniform crossover, and bitflip mutation.\n\n"; cout.flush(); // Declare variables for the GA parameters and set them to some default values. int length = 512; int popsize = 30; int ngen = 1000; float pmut = 0.001; float pcross = 0.9; int which = GAStatistics::Maximum | GAStatistics::Minimum | GAStatistics::Mean; // Now create the GA and run it. First we create a genome of the type that // we want to use in the GA. The ga doesn't use this genome in the // optimization - it just uses it to clone a population of genomes. GENOME_TYPE genome(length, Objective); // Now that we have the genome, we create the genetic algorithm and set // its parameters - number of generations, mutation probability, and crossover // probability. We tell the ga to keep the single best genome of all the // generations, then tell the GA to evolve itself. GASteadyStateGA ga(genome); ga.populationSize(popsize); ga.nGenerations(ngen); ga.pMutation(pmut); ga.pCrossover(pcross); ga.nBestGenomes(1); // how many of the 'best' we should keep ga.scoreFilename("bog.dat"); // where to dump the statistics ga.flushFrequency(50); // how often to dump the statistics ga.selectScores(which); #ifndef USE_GNU GA1DBinStrUniformCrossover cro; ga.crossover(cro); #endif ga.evolve(); cout << "best individual is:\n" << ga.statistics().bestIndividual() << "\n"; cout << "generational data are in 'bog.dat'\n"; return 0; } // This is the objective function. All it does is check for alternating 0s and // 1s. If the gene is odd and contains a 1, the fitness is incremented by 1. // If the gene is even and contains a 0, the fitness is incremented by 1. No // penalties are assigned. float Objective(GAGenome & c) { GENOME_TYPE & genome = (GENOME_TYPE &)c; float score=0.0; for(int i=0; i #include #include #include /* We use subtraction of (char *)0 instead of casting to int because on word-addressable machines a simple cast to int may ignore the byte-within-word field of the pointer. */ #ifndef __PTR_TO_INT #define __PTR_TO_INT(P) ((P) - (char *)0) #endif #ifndef __INT_TO_PTR #define __INT_TO_PTR(P) ((P) + (char *)0) #endif Obstack::Obstack(int size, int alignment) { alignmentmask = alignment - 1; chunksize = size; chunk = 0; nextfree = objectbase = 0; chunklimit = 0; } void Obstack::_free(void* obj) { _obstack_chunk* lp; _obstack_chunk* plp; lp = chunk; while (lp != 0 && ((void*)lp > obj || (void*)(lp)->limit < obj)) { plp = lp -> prev; delete [] (char*)lp; lp = plp; } if (lp) { objectbase = nextfree = (char *)(obj); chunklimit = lp->limit; chunk = lp; } else if (obj != 0) (*lib_error_handler)("Obstack", "deletion of nonexistent obj"); } void Obstack::newchunk(int size) { _obstack_chunk* old_chunk = chunk; _obstack_chunk* new_chunk; long new_size; int obj_size = nextfree - objectbase; new_size = (obj_size + size) << 1; if (new_size < chunksize) new_size = chunksize; new_chunk = chunk = new (operator new (new_size)) _obstack_chunk; new_chunk->prev = old_chunk; new_chunk->limit = chunklimit = (char *) new_chunk + new_size; memcpy((void*)new_chunk->contents, (void*)objectbase, obj_size); objectbase = new_chunk->contents; nextfree = objectbase + obj_size; } void* Obstack::finish() { void* value = (void*) objectbase; nextfree = __INT_TO_PTR (__PTR_TO_INT (nextfree + alignmentmask) & ~alignmentmask); if (nextfree - (char*)chunk > chunklimit - (char*)chunk) nextfree = chunklimit; objectbase = nextfree; return value; } int Obstack::contains(void* obj) // true if obj somewhere in Obstack { _obstack_chunk* ch; for (ch = chunk; ch != 0 && (obj < (void*)ch || obj >= (void*)(ch->limit)); ch = ch->prev); return ch != 0; } int Obstack::OK() { int v = chunksize > 0; // valid size v &= alignmentmask != 0; // and alignment v &= chunk != 0; v &= objectbase >= chunk->contents; v &= nextfree >= objectbase; v &= nextfree <= chunklimit; v &= chunklimit == chunk->limit; _obstack_chunk* p = chunk; // allow lots of chances to find bottom! long x = LONG_MAX; while (p != 0 && x != 0) { --x; p = p->prev; } v &= x > 0; if (!v) (*lib_error_handler)("Obstack", "invariant failure"); return v; } galib247/examples/gnu/Obstack.h0100644003643600364360000001053610573535475015617 0ustar mwallmwall// This may look like C code, but it is really -*- C++ -*- /* Copyright (C) 1988 Free Software Foundation written by Doug Lea (dl@rocky.oswego.edu) This file is part of the GNU C++ Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _Obstack_h #ifdef __GNUG__ #pragma interface #endif #define _Obstack_h 1 #include #include #undef OK class Obstack { struct _obstack_chunk { char* limit; _obstack_chunk* prev; char contents[4]; }; protected: long chunksize; _obstack_chunk* chunk; char* objectbase; char* nextfree; char* chunklimit; int alignmentmask; void _free(void* obj); void newchunk(int size); public: Obstack(int size = 4080, int alignment = 4); // 4080=4096-mallocslop ~Obstack(); void* base(); void* next_free(); int alignment_mask(); int chunk_size(); int size(); int room(); int contains(void* p); // does Obstack hold pointer p? void grow(const void* data, int size); void grow(const void* data, int size, char terminator); void grow(const char* s); void grow(char c); void grow_fast(char c); void blank(int size); void blank_fast(int size); void* finish(); void* finish(char terminator); void* copy(const void* data, int size); void* copy(const void* data, int size, char terminator); void* copy(const char* s); void* copy(char c); void* alloc(int size); void free(void* obj); void shrink(int size = 1); // suggested by ken@cs.rochester.edu int OK(); // rep invariant }; inline Obstack::~Obstack() { _free(0); } inline void* Obstack::base() { return objectbase; } inline void* Obstack::next_free() { return nextfree; } inline int Obstack::alignment_mask() { return alignmentmask; } inline int Obstack::chunk_size() { return chunksize; } inline int Obstack::size() { return nextfree - objectbase; } inline int Obstack::room() { return chunklimit - nextfree; } inline void Obstack:: grow(const void* data, int size) { if (nextfree+size > chunklimit) newchunk(size); memcpy(nextfree, data, size); nextfree += size; } inline void Obstack:: grow(const void* data, int size, char terminator) { if (nextfree+size+1 > chunklimit) newchunk(size+1); memcpy(nextfree, data, size); nextfree += size; *(nextfree)++ = terminator; } inline void Obstack:: grow(const char* s) { grow((const void*)s, strlen(s), 0); } inline void Obstack:: grow(char c) { if (nextfree+1 > chunklimit) newchunk(1); *(nextfree)++ = c; } inline void Obstack:: blank(int size) { if (nextfree+size > chunklimit) newchunk(size); nextfree += size; } inline void* Obstack::finish(char terminator) { grow(terminator); return finish(); } inline void* Obstack::copy(const void* data, int size) { grow (data, size); return finish(); } inline void* Obstack::copy(const void* data, int size, char terminator) { grow(data, size, terminator); return finish(); } inline void* Obstack::copy(const char* s) { grow((const void*)s, strlen(s), 0); return finish(); } inline void* Obstack::copy(char c) { grow(c); return finish(); } inline void* Obstack::alloc(int size) { blank(size); return finish(); } inline void Obstack:: free(void* obj) { if (obj >= (void*)chunk && obj<(void*)chunklimit) nextfree = objectbase = (char *) obj; else _free(obj); } inline void Obstack:: grow_fast(char c) { *(nextfree)++ = c; } inline void Obstack:: blank_fast(int size) { nextfree += size; } inline void Obstack:: shrink(int size) // from ken@cs.rochester.edu { if (nextfree >= objectbase + size) nextfree -= size; } #endif galib247/examples/gnu/README0100644003643600364360000000327310573535475014740 0ustar mwallmwallGNU BitString object and GAlib mbwall 19sep95 This directory contains some objects from the GNU library (libg++) that can be used with GAlib. In particular, I have implemented a set of GAlib operators for use with the GNU BitString object. See the makefile for specifics, but basically you can compile a mini-library using the code in this directory then link to that as well as GAlib when you compile your program. The GAlib-specific files are bitstr.C, bitstr.h, and gnuex.C. bitstr.C and bitstr.h define the new genome class, and gnuex.C contains the main program that runs the GA. I had to modify the GNU files a bit in order to make them work cross-platform. No major changes, just tweaks to the includes and removal of libg++ dependencies that I don't need for this example. This code has been tested on various UNIX machines. I do not know if or how well it work on DOS and/or Mac platforms. At this point I do not have time to try to compile GNU code on those machines (especially when the code does such lowlevel bit operations). COPYRIGHT and LICENSING ISSUES The code in this directory is protected under the terms of the GNU public license (see the file COPYING for details). Under the terms of that agreement, all of the code in this directory is free for any use. It is included with GAlib as an example of how to integrate GAlib with other data structures. Please see the copyright notices in each file for specific ownership. As works that use the GNU library (or parts thereof), the GAlib-specific files are Copyright MIT, but they are available for copying and distribution under the terms of the GNU public license agreement, not the terms of the general GAlib licensing agreement. galib247/examples/graphic/0040755003643600364360000000000010573536000014663 5ustar mwallmwallgalib247/examples/graphic/bitmaps/0040755003643600364360000000000010573536000016322 5ustar mwallmwallgalib247/examples/graphic/bitmaps/ffst.xbm0100644003643600364360000000115310573535500017775 0ustar mwallmwall/* VCR controls bitmap */ /* Copyright (c) 1996 matthew wall, all rights reserved */ #define ffst_width 24 #define ffst_height 24 static unsigned char ffst_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x18, 0x18, 0x18, 0x18, 0x38, 0x38, 0x18, 0x78, 0x78, 0x18, 0xf8, 0xf8, 0x18, 0xf8, 0xf9, 0x19, 0xf8, 0xfb, 0x1b, 0xf8, 0xfb, 0x1b, 0xf8, 0xf9, 0x19, 0xf8, 0xf8, 0x18, 0x78, 0x78, 0x18, 0x38, 0x38, 0x18, 0x18, 0x18, 0x18, 0x08, 0x08, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; galib247/examples/graphic/bitmaps/ffwd.xbm0100644003643600364360000000115310573535500017761 0ustar mwallmwall/* VCR controls bitmap */ /* Copyright (c) 1996 matthew wall, all rights reserved */ #define ffwd_width 24 #define ffwd_height 24 static unsigned char ffwd_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x00, 0xc0, 0xc0, 0x00, 0xc0, 0xc1, 0x01, 0xc0, 0xc3, 0x03, 0xc0, 0xc7, 0x07, 0xc0, 0xcf, 0x0f, 0xc0, 0xdf, 0x1f, 0xc0, 0xdf, 0x1f, 0xc0, 0xcf, 0x0f, 0xc0, 0xc7, 0x07, 0xc0, 0xc3, 0x03, 0xc0, 0xc1, 0x01, 0xc0, 0xc0, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; galib247/examples/graphic/bitmaps/fwds.xbm0100644003643600364360000000115310573535500017776 0ustar mwallmwall/* VCR controls bitmap */ /* Copyright (c) 1996 matthew wall, all rights reserved */ #define fwds_width 24 #define fwds_height 24 static unsigned char fwds_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xc0, 0x00, 0xc0, 0xc0, 0x00, 0xc0, 0xc1, 0x00, 0xc0, 0xc3, 0x00, 0xc0, 0xc7, 0x00, 0xc0, 0xcf, 0x00, 0xc0, 0xdf, 0x00, 0xc0, 0xdf, 0x00, 0xc0, 0xcf, 0x00, 0xc0, 0xc7, 0x00, 0xc0, 0xc3, 0x00, 0xc0, 0xc1, 0x00, 0xc0, 0xc0, 0x00, 0x40, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; galib247/examples/graphic/bitmaps/gaview.xbm0100644003643600364360000000370410573535500020321 0ustar mwallmwall/* microscope-on-chromosomes bitmap */ /* Copyright (c) 1996 matthew wall, all rights reserved */ #define gaview_width 48 #define gaview_height 48 static unsigned char gaview_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x7e, 0x00, 0x00, 0x00, 0x80, 0x07, 0xf0, 0x00, 0x00, 0x00, 0xc0, 0x11, 0xc6, 0x01, 0x00, 0x00, 0x60, 0x18, 0x01, 0x03, 0x40, 0x00, 0x70, 0x10, 0x03, 0x07, 0x48, 0x00, 0x30, 0x20, 0x22, 0x06, 0x88, 0x00, 0x38, 0x60, 0x23, 0x8e, 0x88, 0x00, 0x18, 0xc0, 0xa1, 0x4d, 0x51, 0x00, 0x1c, 0x42, 0x21, 0x5d, 0x51, 0x00, 0x1c, 0x42, 0x41, 0x9d, 0x20, 0x00, 0x6c, 0x61, 0x81, 0x5d, 0x51, 0x00, 0x4c, 0x41, 0x81, 0x58, 0x92, 0x00, 0x4c, 0x41, 0x83, 0x98, 0x92, 0x00, 0x5c, 0x41, 0x83, 0x9c, 0x92, 0x00, 0xdc, 0x40, 0x42, 0x9c, 0x52, 0x00, 0x98, 0x41, 0x42, 0x8c, 0x50, 0x00, 0x38, 0x61, 0x42, 0x0e, 0x00, 0x00, 0x30, 0x21, 0x06, 0x06, 0x00, 0x00, 0x70, 0x20, 0x06, 0x07, 0x00, 0x00, 0x60, 0x60, 0x04, 0x03, 0x00, 0x00, 0xc0, 0x41, 0xc0, 0x01, 0x00, 0x00, 0x80, 0x07, 0xf0, 0x03, 0x00, 0x00, 0x00, 0x3f, 0x7e, 0x07, 0x00, 0x00, 0x00, 0xfc, 0x1f, 0x3e, 0x00, 0x00, 0x00, 0xf0, 0x07, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x43, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x4f, 0x00, 0x00, 0x00, 0x12, 0xe0, 0x8f, 0x00, 0x00, 0x00, 0x12, 0xc9, 0x9f, 0x00, 0x00, 0x00, 0x14, 0xc5, 0x7f, 0x00, 0x00, 0x50, 0x14, 0x45, 0x7f, 0x00, 0x40, 0x51, 0x08, 0x82, 0xfe, 0x00, 0x80, 0x20, 0x14, 0x45, 0xfd, 0x01, 0x40, 0x51, 0x24, 0x4a, 0xfa, 0x03, 0x40, 0xa2, 0x24, 0x89, 0xf2, 0x07, 0x40, 0x92, 0x28, 0x89, 0xf2, 0x0f, 0x00, 0x90, 0x28, 0x85, 0xd2, 0x1f, 0x00, 0x00, 0x24, 0x85, 0xd0, 0x1f, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; galib247/examples/graphic/bitmaps/rew.xbm0100644003643600364360000000115010573535477017642 0ustar mwallmwall/* VCR controls bitmap */ /* Copyright (c) 1996 matthew wall, all rights reserved */ #define rew_width 24 #define rew_height 24 static unsigned char rew_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x03, 0x03, 0x80, 0x83, 0x03, 0xc0, 0xc3, 0x03, 0xe0, 0xe3, 0x03, 0xf0, 0xf3, 0x03, 0xf8, 0xfb, 0x03, 0xf8, 0xfb, 0x03, 0xf0, 0xf3, 0x03, 0xe0, 0xe3, 0x03, 0xc0, 0xc3, 0x03, 0x80, 0x83, 0x03, 0x00, 0x03, 0x03, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; galib247/examples/graphic/bitmaps/stop.xbm0100644003643600364360000000102510573535500020016 0ustar mwallmwall#define stop_width 24 #define stop_height 24 static unsigned char stop_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x01, 0x80, 0xff, 0x01, 0x80, 0xff, 0x01, 0x80, 0xff, 0x01, 0x80, 0xff, 0x01, 0x80, 0xff, 0x01, 0x80, 0xff, 0x01, 0x80, 0xff, 0x01, 0x80, 0xff, 0x01, 0x80, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; galib247/examples/graphic/GAView.ad0100644003643600364360000000157310573535500016322 0ustar mwallmwall! Application defaults for the graphic genetic algorithm program ! Copyright (c) 1996 Matthew Wall ! mbw 17jan96 *bestColor: yellow *populationColor1: green *populationColor2: blue *populationColor3: cyan *populationColor4: orange *populationColor5: red *ga: 2 *genome: 0 *function: 3 *generationsPerStep: 10 *background: thistle4 *leftOffset: 3 *rightOffset: 3 *topOffset: 3 *bottomOffset: 3 *canvas.width: 400 *canvas.height: 300 *canvas.background: black ! these are motif-specific *fontList: -*-helvetica-bold-r-*-*-*-140-*-*-*-*-*-* *score.labelString: score *stats.labelString: stats *params.labelString: params ! these are athena-specific *font: -*-helvetica-bold-r-*-*-*-140-*-*-*-*-*-* *rewind.label: reset *stop.label: stop *step.label: one *some.label: some *evolve.label: all *score.label: score *stats.label: stats *params.label: params galib247/examples/graphic/gaview.C0100644003643600364360000007242310573535500016262 0ustar mwallmwall/* ---------------------------------------------------------------------------- gaview.C mbwall 10apr96 Copyright (c) 1996 Massachusetts Institute of Technology Visual genetic algorithm example code. The program pops up a single window with a set of buttons that control the evolution. You can view an entire population or a single individual. The program reads standard GAlib settings files and understands the usual GAlib command-line options. Apologies for the mix of C and C++ coding styles here, but you get the idea. By the way, this thing looks WAY better when you plot the functions in 3D (using an OpenGL widget rather than the drawing area widget, for example). You can compile this using either motif widgets or the athena widgets, depending on which you have on your system. ---------------------------------------------------------------------------- */ #include #include #include #include #define cout STD_COUT #define cerr STD_CERR #define endl STD_ENDL #define INSTANTIATE_REAL_GENOME #include // comment this line if you don't have MOTIF on your system //#define USE_MOTIF #ifdef USE_MOTIF #include #include #include #include #include #include #include #else #include #include #include #include #include #include #endif #define APP_CLASS "GAView" #define SETTINGS_FILE "settings.txt" #define MAX_POPS 5 typedef struct _AppData { Pixel bestcolor; Pixel popcolor[MAX_POPS]; int geninc; // how many generations in each step XtWorkProcId procid; XtAppContext appc; Widget canvas, counter; GC bestgc, dotgc[MAX_POPS]; GAGenome* genome; GAGeneticAlgorithm* ga; int whichGA; // which genetic algorithm to use int whichGenome; // which genome to use int whichFunction; // which function to use } AppData, *AppDataPtr, **AppDataHdl; static AppData theAppData; // global data for the program int done = 0; // is the program finished yet? #include "bitmaps/gaview.xbm" #ifdef USE_MOTIF #include "bitmaps/rew.xbm" #include "bitmaps/stop.xbm" #include "bitmaps/fwds.xbm" #include "bitmaps/ffst.xbm" #include "bitmaps/ffwd.xbm" typedef struct _BitmapInfo { int width, height; unsigned char *bits; } BitmapInfo; static BitmapInfo bm[] = { {stop_width, stop_height, (unsigned char *)stop_bits}, {rew_width, rew_height, (unsigned char *)rew_bits}, {fwds_width, fwds_height, (unsigned char *)fwds_bits}, {ffst_width, ffst_height, (unsigned char *)ffst_bits}, {ffwd_width, ffwd_height, (unsigned char *)ffwd_bits} }; enum { bmStop, bmRewind, bmForwardStop, bmFastForwardStop, bmFastForward, nBitmaps }; #endif Widget ConstructWidgets(Widget); void UpdateCounter(GAGeneticAlgorithm*); static Boolean Evolve(int); void QuitCB(Widget, XtPointer, XtPointer); void InitCB(Widget, XtPointer, XtPointer); void DrawCB(Widget, XtPointer, XtPointer); void ResetCB(Widget, XtPointer, XtPointer); void StopCB(Widget, XtPointer, XtPointer); void StepCB(Widget, XtPointer, XtPointer); void EvolveSomeCB(Widget, XtPointer, XtPointer); void EvolveCB(Widget, XtPointer, XtPointer); void DumpStatsCB(Widget, XtPointer, XtPointer); void DumpParamsCB(Widget, XtPointer, XtPointer); void DumpScoreCB(Widget, XtPointer, XtPointer); void DrawPopulation(Widget, const GAPopulation&, GC, GC); static char *fallbacks[] = { "*shell.title: gaview", "*background: thistle4", "*canvas.background: black", "*leftOffset: 3", "*rightOffset: 3", "*topOffset: 3", "*bottomOffset: 3", "*canvas.width: 400", "*canvas.height: 300", "*bestColor: green", "*populationColor1: yellow", "*populationColor2: blue", "*populationColor3: red", "*populationColor4: purple", "*populationColor5: cyan", "*ga: 2", "*genome: 0", "*function: 3", "*generationsPerStep: 10", // motif-specific fallbacks "*fontList: -*-helvetica-bold-r-*-*-*-140-*-*-*-*-*-*", "*score.labelString: score", "*stats.labelString: stats", "*params.labelString: params", // athena-specific fallbacks "*font: -*-helvetica-bold-r-*-*-*-140-*-*-*-*-*-*", "*rewind.label: reset", "*stop.label: stop", "*step.label: one", "*some.label: some", "*evolve.label: all", "*score.label: score", "*stats.label: stats", "*params.label: params", (char *)NULL }; static XtResource resources[] = { #define Offset(field) (XtOffset(AppDataPtr, field)) {"bestColor", XtCForeground, XtRPixel, sizeof(Pixel), Offset(bestcolor), XtRString, (XtPointer)XtDefaultForeground}, {"populationColor1", XtCForeground, XtRPixel, sizeof(Pixel), Offset(popcolor[0]), XtRString, (XtPointer)XtDefaultForeground}, {"populationColor2", XtCForeground, XtRPixel, sizeof(Pixel), Offset(popcolor[1]), XtRString, (XtPointer)XtDefaultForeground}, {"populationColor3", XtCForeground, XtRPixel, sizeof(Pixel), Offset(popcolor[2]), XtRString, (XtPointer)XtDefaultForeground}, {"populationColor4", XtCForeground, XtRPixel, sizeof(Pixel), Offset(popcolor[3]), XtRString, (XtPointer)XtDefaultForeground}, {"populationColor5", XtCForeground, XtRPixel, sizeof(Pixel), Offset(popcolor[4]), XtRString, (XtPointer)XtDefaultForeground}, {"ga", "GA", XtRInt, sizeof(int), Offset(whichGA), XtRImmediate, (XtPointer)2}, {"genome", "Genome", XtRInt, sizeof(int), Offset(whichGenome), XtRImmediate, (XtPointer)0}, {"function", "Function", XtRInt, sizeof(int), Offset(whichFunction), XtRImmediate, (XtPointer)3}, {"generationsPerStep", "GenerationsPerStep", XtRInt, sizeof(int), Offset(geninc), XtRImmediate, (XtPointer)10} #undef Offset }; static XrmOptionDescRec options[] = { {"ga", "ga", XrmoptionSepArg, 0}, {"genome", "genome", XrmoptionSepArg, 0}, {"function", "function", XrmoptionSepArg, 0}, {"geninc", "generationsPerStep", XrmoptionSepArg, 0} }; float RealObjective(GAGenome&); float Bin2DecObjective(GAGenome&); typedef float (*Function)(float, float); float Function1(float x, float y); float Function2(float x, float y); float Function3(float x, float y); float Function4(float x, float y); Function obj[] = { Function1, Function2, Function3, Function4 }; float minx[] = {-6, -60, -500, -10 }; float maxx[] = { 6, 60, 500, 10 }; float ai[25],bi[25]; int main(int argc, char** argv) { cout << "Graphic genetic algorithm demonstration program.\n\n"; cout << "This program understands the standard GAlib and Xt\n"; cout << "arguments plus the following:\n\n"; cout << " function which function to solve\n"; cout << " 0 loaf of bread with 4 smooth humps\n"; cout << " 1 Shekel's foxholes from DeJong\n"; cout << " 2 Schwefel's nasty function\n"; cout << " 3 concentric rings (ripple in a pond) (default)\n"; cout << " ga specify which genetic algorithm to use\n"; cout << " 0 incremental genetic algorithm\n"; cout << " 1 simple genetic algorithm\n"; cout << " 2 steady-state genetic algorithm (default)\n"; cout << " 3 deme genetic algorithm\n"; cout << " genome specify which genome to use\n"; cout << " 0 real number genome (default)\n"; cout << " 1 binary-to-decimal genome\n"; cout << "\n"; cout << endl; // make the application widget, grab resource, and parse command line Widget toplevel = XtAppInitialize(&theAppData.appc, APP_CLASS, options, XtNumber(options), &argc, argv, fallbacks, (ArgList)NULL, 0); XtGetApplicationResources(toplevel, (XtPointer) &theAppData, resources, XtNumber(resources), NULL, 0); // do some setup for one of the functions for (int j=0; j<25; j++) { ai[j] = 16 * ((j % 5) -2); bi[j] = 16 * ((j / 5) -2); } // Create the appropriate genome and genetic algorithm if(theAppData.whichGenome == 1) { GABin2DecPhenotype map; map.add(31, minx[theAppData.whichFunction], maxx[theAppData.whichFunction]); map.add(31, minx[theAppData.whichFunction], maxx[theAppData.whichFunction]); theAppData.genome = new GABin2DecGenome(map, Bin2DecObjective); } else { GARealAlleleSet alleleset(minx[theAppData.whichFunction], maxx[theAppData.whichFunction]); theAppData.genome = new GARealGenome(2, alleleset, RealObjective); } if(theAppData.whichGA == 0) theAppData.ga = new GAIncrementalGA(*theAppData.genome); else if(theAppData.whichGA == 1) theAppData.ga = new GASimpleGA(*theAppData.genome); else if(theAppData.whichGA == 3) theAppData.ga = new GADemeGA(*theAppData.genome); else theAppData.ga = new GASteadyStateGA(*theAppData.genome); // Now set up the genetic algorithm parameters theAppData.ga->parameters(SETTINGS_FILE); theAppData.ga->parameters(argc, argv); theAppData.ga->initialize(); // we don't allow too many populations (due to our color limit) if(theAppData.whichGA == 3) { int val; theAppData.ga->get(gaNnPopulations, &val); if(val > MAX_POPS) { val = MAX_POPS; theAppData.ga->set(gaNnPopulations, val); cerr << "this demo limits the number of populations to "<generation()); str = XmStringLtoRCreate(txt, XmSTRING_DEFAULT_CHARSET); XtVaSetValues(theAppData.counter, XmNlabelString, str, NULL); XmStringFree(str); #else static char txt[62]; sprintf(txt, "%d", ga->generation()); XtVaSetValues(theAppData.counter, XtNlabel, txt, NULL); #endif } Boolean Evolve(int n){ if((n < 0 && theAppData.ga->done() == gaFalse) || theAppData.ga->generation() < n){ theAppData.ga->step(); DrawCB(theAppData.canvas, (XtPointer)&theAppData, 0); UpdateCounter(theAppData.ga); return False; } return True; } void ResetCB(Widget, XtPointer cd, XtPointer){ AppDataPtr data = (AppDataPtr)cd; if(data->procid){ XtRemoveWorkProc(data->procid); data->procid = 0; } data->ga->initialize(); DrawCB(data->canvas, data, 0); UpdateCounter(data->ga); } void StopCB(Widget, XtPointer cd, XtPointer){ AppDataPtr data = (AppDataPtr)cd; if(data->procid){ XtRemoveWorkProc(data->procid); data->procid = 0; } } void StepCB(Widget, XtPointer cd, XtPointer){ AppDataPtr data = (AppDataPtr)cd; Evolve(data->ga->generation() + 1); } void EvolveSomeCB(Widget, XtPointer cd, XtPointer){ AppDataPtr data = (AppDataPtr)cd; data->procid = XtAppAddWorkProc(data->appc, (XtWorkProc)Evolve, (XtPointer)(data->ga->generation() + data->geninc)); } void EvolveCB(Widget, XtPointer cd, XtPointer){ AppDataPtr data = (AppDataPtr)cd; data->procid = XtAppAddWorkProc(data->appc, (XtWorkProc)Evolve,(XtPointer)(-1)); } void QuitCB(Widget, XtPointer, XtPointer){ done = 1; } void DumpStatsCB(Widget, XtPointer cd, XtPointer){ cerr << "\nstatistics are:\n" << ((GAGeneticAlgorithm*)cd)->statistics() << "\n"; } void DumpParamsCB(Widget, XtPointer cd, XtPointer){ cerr << "\nparameters are:\n" << ((GAGeneticAlgorithm*)cd)->parameters() << "\n"; } void DumpScoreCB(Widget, XtPointer cd, XtPointer){ cerr << "\nbest individual score is: " << ((GAGeneticAlgorithm*)cd)->population().best().score() << "\n"; } // This routine draws the entire population or a single individual depending // on the value of the single flag. It needs to know how much of a // buffer to use for spacing between individuals. We assume that each // individual draws from its centroid. // This is much more nicely done when you derive your own genome that includes // a draw routine and all the graphics info in it, but for the purpose of this // example we'll just make a separate function that draws the genome and others // that return the graphics info about the genomes. #define BUF 10 void DrawCB(Widget w, XtPointer cd, XtPointer){ AppDataPtr data = (AppDataPtr)cd; XClearWindow(XtDisplay(w), XtWindow(w)); if(data->whichGA == 3) { GADemeGA* ga = (GADemeGA*)data->ga; for(int i=0; inPopulations(); i++) DrawPopulation(w, ga->population(i), data->dotgc[i], data->dotgc[i]); } else { DrawPopulation(w, data->ga->population(), data->dotgc[0], data->bestgc); } } void DrawPopulation(Widget widget, const GAPopulation& pop, GC dotgc, GC bestgc) { static int npts = 0; static XPoint* pts = 0; if(npts != pop.size()) { npts = pop.size(); delete [] pts; pts = new XPoint [npts]; } Dimension width = 0, height = 0; XtVaGetValues(widget, XtNwidth, &width, XtNheight, &height, NULL); Dimension w = width - 2 * BUF; Dimension h = height - 2 * BUF; Dimension d = (w < h ? w : h); w -= d; h -= d; Dimension originx = BUF + w/2; Dimension originy = BUF + h/2; float factor = (float)d; factor /= (maxx[theAppData.whichFunction] - minx[theAppData.whichFunction]); int xbest = 0, ybest = 0; if(theAppData.whichGenome == 1) { for(int i=0; i #include #include #include #include #define cout STD_COUT #define cerr STD_CERR #define endl STD_ENDL #define ifstream STD_IFSTREAM #define ostream STD_OSTREAM // comment this line if you don't have MOTIF on your system //#define USE_MOTIF #ifdef USE_MOTIF #include #include #include #include #include #else #include #include #include #include #include #include #endif // Set this up for your favorite TSP. The sample one is a contrived problem // with the towns laid out in a grid (so it is easy to figure out what the // shortest distance is, and there are many different paths with the same // shortest path). File format is that used by the TSPLIB problems. You can // grab more problems from // // // Apologies for using fixed-length arrays. But this is an example, not // production code ;) #define MAX_TOWNS 50 #define TSP_FILE "tsp_rect_20.txt" float DISTANCE[MAX_TOWNS][MAX_TOWNS]; double x[MAX_TOWNS],y[MAX_TOWNS]; int ntowns = 0; float width, height; float Objective(GAGenome&); int Mutator(GAGenome&, float); void Initializer(GAGenome&); float Comparator(const GAGenome&, const GAGenome&); int Crossover(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*); void ERXOneChild(const GAGenome&, const GAGenome&, GAGenome*); #ifdef USE_MOTIF #include "bitmaps/rew.xbm" #include "bitmaps/stop.xbm" #include "bitmaps/fwds.xbm" #include "bitmaps/ffst.xbm" #include "bitmaps/ffwd.xbm" typedef struct _BitmapInfo { int width, height; unsigned char *bits; } BitmapInfo; static BitmapInfo bm[] = { {stop_width, stop_height, (unsigned char *)stop_bits}, {rew_width, rew_height, (unsigned char *)rew_bits}, {fwds_width, fwds_height, (unsigned char *)fwds_bits}, {ffst_width, ffst_height, (unsigned char *)ffst_bits}, {ffwd_width, ffwd_height, (unsigned char *)ffwd_bits} }; enum { bmStop, bmRewind, bmForward, bmForwardStop, bmFastForward, nBitmaps }; #endif Widget ConstructWidgets(Widget); void QuitCB(Widget, XtPointer, XtPointer); void InitCB(Widget, XtPointer, XtPointer); void DrawCB(Widget, XtPointer, XtPointer); void ResetCB(Widget, XtPointer, XtPointer); void StopCB(Widget, XtPointer, XtPointer); void StepCB(Widget, XtPointer, XtPointer); void EvolveSomeCB(Widget, XtPointer, XtPointer); void EvolveCB(Widget, XtPointer, XtPointer); void DrawIndividual(GAGenome&, Display*, Drawable, GC, int, int); void Refresh(); static int geninc = 10; static char *fallbacks[] = { ".function: 0", "*canvas.width: 500", "*canvas.height: 300", // motif-specific fallbacks "*fontList: -*-helvetica-bold-r-*-*-*-140-*-*-*-*-*-*", // athena-specific fallbacks "*font: -*-helvetica-bold-r-*-*-*-140-*-*-*-*-*-*", (char *)NULL }; static XtWorkProcId procid; static Boolean Evolve(int); static XtAppContext appc; static Widget canvas; static GAGeneticAlgorithm* ga; static GC thegc; static int done = 0; int main(int argc, char** argv) { cout << "Travelling salesperson demonstration program. Use the 'ga'\n"; cout << "option to specify which type of genetic algorithm you would\n"; cout << "like to use to do the evolution. Options for the ga are:\n"; cout << " 1 - steady-state\n"; cout << " 2 - deterministic crowding\n"; cout << " 3 - simple\n"; cout << "\n"; cout.flush(); // read in the cities and create the DISTANCE-matrix double dump; ifstream in(TSP_FILE); if(!in) { cerr << "could not read data file " << TSP_FILE << "\n"; exit(1); } ntowns=0; do { in >> dump; if(!in.eof()) { in >> x[ntowns]; in >> y[ntowns]; ntowns++; } } while(!in.eof() && ntowns < MAX_TOWNS); in.close(); if(ntowns >= MAX_TOWNS) { cerr << "data file contains more towns than allowed for in the fixed\n"; cerr << "arrays. Recompile the program with larger arrays or try a\n"; cerr << "smaller problem.\n"; exit(1); } double dx,dy; int i, j; for(i=0;i x[i]) ? maxx : x[i]; } for(i=0; i y[i]) ? maxy : y[i]; } width = maxx - minx; height = maxy - miny; // figure out which GA to use int whichGA = 0; for(int ii=1; ii= argc){ cerr << argv[0] << ": you must specify a ga:\n"; cerr << " 1 - steady-state\n"; cerr << " 2 - deterministic crowding\n"; cerr << " 3 - simple\n"; cerr << "\n"; exit(1); } else{ whichGA = atoi(argv[ii]); continue; } } } GAListGenome genome(Objective); genome.initializer(::Initializer); genome.mutator(::Mutator); genome.comparator(::Comparator); genome.crossover(::Crossover); switch(whichGA){ case 2: { ga = new GADCrowdingGA(genome); cerr << " using deterministic crowding GA...\n"; } break; case 3: { ga = new GASimpleGA(genome); GASigmaTruncationScaling sigma1; ga->scaling(sigma1); cerr << " using simple GA...\n"; } break; case 1: default: { ga = new GASteadyStateGA(genome); GASigmaTruncationScaling sigma; ga->scaling(sigma); ga->set(gaNpReplacement, 0.5); cerr << " using steady-state GA...\n"; } break; } ga->minimize(); ga->crossover(Crossover); ga->populationSize(50); ga->nGenerations(10000); ga->pMutation(0.3); ga->pCrossover(1.0); ga->selectScores(GAStatistics::AllScores); ga->parameters(argc, argv); ga->initialize(); Widget toplevel = XtAppInitialize(&appc, "TSPView", (XrmOptionDescRec*)NULL, 0, &argc, argv, fallbacks, (ArgList)NULL, 0); Widget shell = ConstructWidgets(toplevel); XtRealizeWidget(shell); XtMapWidget(shell); static Atom wmDeleteWindow; wmDeleteWindow = XInternAtom(XtDisplay(toplevel), "WM_DELETE_WINDOW", False); #ifdef USE_MOTIF XmAddWMProtocolCallback(shell, wmDeleteWindow, QuitCB, (XtPointer)0); #else XSetWMProtocols(XtDisplay(toplevel), XtWindow(toplevel), &wmDeleteWindow, 1); #endif XtGCMask valueMask = GCFunction | GCLineWidth; XGCValues gcValues; gcValues.function = GXcopy; gcValues.line_width = 2; thegc = XCreateGC(XtDisplay(toplevel), RootWindowOfScreen(XtScreen(toplevel)), valueMask, &gcValues); while(!done){ XEvent event; XtAppNextEvent(appc, &event); XtDispatchEvent(&event); } XFreeGC(XtDisplay(toplevel), thegc); delete ga; return 0; } Boolean Evolve(int n){ if((n < 0 && ga->done() == gaFalse) || ga->generation() < n){ ga->step(); if(ga->generation() % 10 == 0){ cerr << "generation: " << ga->generation() << "\t"; cerr<<"best score is "<< ga->population().best().score()<<"\n"; } Refresh(); return False; } return True; } void ResetCB(Widget, XtPointer cd, XtPointer){ GAGeneticAlgorithm* ga = (GAGeneticAlgorithm*)cd; if(procid){ XtRemoveWorkProc(procid); procid = 0; } cerr << "initialized\n"; ga->initialize(); Refresh(); } void StopCB(Widget, XtPointer, XtPointer){ if(procid){ XtRemoveWorkProc(procid); procid = 0; } } void StepCB(Widget, XtPointer cd, XtPointer){ GAGeneticAlgorithm* ga = (GAGeneticAlgorithm*)cd; Evolve(ga->generation() + 1); } void EvolveSomeCB(Widget, XtPointer cd, XtPointer){ GAGeneticAlgorithm* ga = (GAGeneticAlgorithm*)cd; procid = XtAppAddWorkProc(appc, (XtWorkProc)Evolve, (XtPointer)(ga->generation() + geninc)); } void EvolveCB(Widget, XtPointer, XtPointer){ procid = XtAppAddWorkProc(appc, (XtWorkProc)Evolve, (XtPointer)(-1)); } void QuitCB(Widget, XtPointer, XtPointer){ done = 1; } #define SCALE 10 #define BUF 10 void DrawCB(Widget w, XtPointer cd, XtPointer){ GAGeneticAlgorithm* ga = (GAGeneticAlgorithm*)cd; XClearWindow(XtDisplay(w), XtWindow(w)); int nrows = (int)sqrt(1.3333333333 * ga->population().size()) + 1; int ncols = ga->population().size() / nrows + 1; int idx = 0; for(int i=0; ipopulation().size(); i++){ for(int j=0; jpopulation().size(); j++){ int a = BUF + i*(SCALE*width+BUF); int b = BUF + j*(SCALE*height+BUF); DrawIndividual(ga->population().best(idx++), XtDisplay(w), XtWindow(w), thegc, a, b); } } } void Refresh() { DrawCB(canvas, (XtPointer)ga, 0); } // draw an individual genome at the specified coordinates (in Xwindows space) // Draw the paths that link the towns. We draw a complete, closed loop // so go for one more than the number of nodes in the list. void DrawIndividual(GAGenome& g, Display* display, Drawable drawable, GC gc, int xx, int yy) { GAListGenome& genome = (GAListGenome&)g; for(int i=0; i & genome = (GAListGenome &)g; float dist = 0; if(genome.head()) { for(int i=0; i &child=(GAListGenome &)g; while(child.head()) child.destroy(); // destroy any pre-existing list int i,town; static int visit[MAX_TOWNS]; memset(visit, 0, MAX_TOWNS*sizeof(int)); town=GARandomInt(0,ntowns-1); visit[town]=1; child.insert(town,GAListBASE::HEAD); // the head node for( i=1; i &child=(GAListGenome &)g; register int n, i; if ((GARandomFloat() >= pmut) || (pmut <= 0)) return 0; n = child.size(); if (GARandomFloat()<0.5) { child.swap(GARandomInt(0,n-1),GARandomInt(0,n-1)); // swap only one time } else { int nNodes = GARandomInt(1,((int)(n/2-1))); // displace nNodes child.warp(GARandomInt(0,n-1)); // with or without GAList TmpList; // inversion for(i=0;i &mate1=(GAListGenome &)g1; GAListGenome &mate2=(GAListGenome &)g2; GAListGenome &sis=(GAListGenome &)*c1; int i,j,k,t1,t2,town; static char CM[MAX_TOWNS][MAX_TOWNS],visit[MAX_TOWNS]; memset(CM, 0, MAX_TOWNS*MAX_TOWNS*sizeof(char)); memset(visit, 0, MAX_TOWNS*sizeof(char)); while (sis.head()) sis.destroy(); // create connection matrix mate1.head(); for(j=0; j PossFollowList; GAList FollowersList[5]; while (PossFollowList.head()) PossFollowList.destroy(); for(k=0; k<5; k++) { while (FollowersList[k].head()) FollowersList[k].destroy(); } // select the following town with the minimal no of next folling towns int nPoss,nFollow; for(i=1; i &a = (GAListGenome &)g1; GAListGenome &b = (GAListGenome &)g2; int i,j,t1,t2; float dist=ntowns; static char CM1[MAX_TOWNS][MAX_TOWNS],CM2[MAX_TOWNS][MAX_TOWNS]; memset(CM1, 0, MAX_TOWNS*MAX_TOWNS*sizeof(char)); memset(CM2, 0, MAX_TOWNS*MAX_TOWNS*sizeof(char)); // create connection matrix CM1 a.head(); for(i=0; i::write(ostream & os) const { int *cur, *head; GAListIter iter(*this); if((head=iter.head()) != 0) os << *head << " "; for(cur=iter.next(); cur && cur != head; cur=iter.next()) os << *cur << " "; return os.fail() ? 1 : 0; } // If your compiler does not do automatic instantiation (e.g. g++ 2.6.8), // then define the NO_AUTO_INST directive. #ifdef NO_AUTO_INST #include #include template class GAList; template class GAListGenome; #endif // Here are two versions of the graphic interface. One version for those of // you with MOTIF on your systems, and one version for those of you with only // the athena widget set. Sorry, no Windoze version yet... #ifdef USE_MOTIF Widget ConstructWidgets(Widget toplevel) { Widget shell = XtVaCreatePopupShell("shell", topLevelShellWidgetClass, toplevel, NULL); Widget form = XtVaCreateManagedWidget("form", xmFormWidgetClass, shell, NULL); Pixmap pix; Pixel fg, bg; unsigned int depth; XtVaGetValues(form, XmNforeground, &fg, XmNbackground, &bg, XmNdepth, &depth, NULL); pix = XCreatePixmapFromBitmapData(XtDisplay(form), RootWindowOfScreen(XtScreen(form)), (char *)bm[bmRewind].bits, bm[bmRewind].width, bm[bmRewind].height, fg, bg, depth); Widget rewind = XtVaCreateManagedWidget("rewind", xmPushButtonWidgetClass, form, XmNbottomAttachment, XmATTACH_FORM, XmNlabelType, XmPIXMAP, XmNlabelPixmap, pix, NULL); pix = XCreatePixmapFromBitmapData(XtDisplay(form), RootWindowOfScreen(XtScreen(form)), (char *)bm[bmStop].bits, bm[bmStop].width, bm[bmStop].height, fg, bg, depth); Widget stop = XtVaCreateManagedWidget("stop", xmPushButtonWidgetClass, form, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, rewind, XmNbottomAttachment, XmATTACH_FORM, XmNlabelType, XmPIXMAP, XmNlabelPixmap, pix, NULL); pix = XCreatePixmapFromBitmapData(XtDisplay(form), RootWindowOfScreen(XtScreen(form)), (char *)bm[bmForward].bits, bm[bmForward].width, bm[bmForward].height, fg, bg, depth); Widget step = XtVaCreateManagedWidget("step", xmPushButtonWidgetClass, form, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, stop, XmNbottomAttachment, XmATTACH_FORM, XmNlabelType, XmPIXMAP, XmNlabelPixmap, pix, NULL); pix = XCreatePixmapFromBitmapData(XtDisplay(form), RootWindowOfScreen(XtScreen(form)), (char *)bm[bmForwardStop].bits, bm[bmForwardStop].width, bm[bmForwardStop].height, fg, bg, depth); Widget some = XtVaCreateManagedWidget("some", xmPushButtonWidgetClass, form, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, step, XmNbottomAttachment, XmATTACH_FORM, XmNlabelType, XmPIXMAP, XmNlabelPixmap, pix, NULL); pix = XCreatePixmapFromBitmapData(XtDisplay(form), RootWindowOfScreen(XtScreen(form)), (char *)bm[bmFastForward].bits, bm[bmFastForward].width, bm[bmFastForward].height, fg, bg, depth); Widget evolve = XtVaCreateManagedWidget("evolve", xmPushButtonWidgetClass, form, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, some, XmNbottomAttachment, XmATTACH_FORM, XmNlabelType, XmPIXMAP, XmNlabelPixmap, pix, NULL); XtAddCallback(rewind, XmNactivateCallback, ResetCB, (XtPointer)ga); XtAddCallback(stop, XmNactivateCallback, StopCB, (XtPointer)ga); XtAddCallback(step, XmNactivateCallback, StepCB, (XtPointer)ga); XtAddCallback(some, XmNactivateCallback, EvolveSomeCB, (XtPointer)ga); XtAddCallback(evolve, XmNactivateCallback, EvolveCB, (XtPointer)ga); canvas = XtVaCreateManagedWidget("canvas", xmDrawingAreaWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, rewind, NULL); XtAddCallback(canvas, XmNexposeCallback, DrawCB, (XtPointer)ga); return shell; } #else void ExposureEH(Widget w, XtPointer cd, XEvent*, Boolean*) { DrawCB(w,cd,0); } Widget ConstructWidgets(Widget toplevel) { Widget form = XtVaCreateManagedWidget("form", formWidgetClass, toplevel, NULL); canvas = XtVaCreateManagedWidget("canvas", widgetClass, form, NULL); XtAddEventHandler(canvas, ExposureMask, False, ExposureEH, (XtPointer)ga); Widget ctrlbox = XtVaCreateManagedWidget("controls", boxWidgetClass, form, XtNfromVert, canvas, XtNorientation, "vertical", NULL); Widget rewind = XtVaCreateManagedWidget("rewind", commandWidgetClass, ctrlbox, NULL); Widget stop = XtVaCreateManagedWidget("stop", commandWidgetClass, ctrlbox, NULL); Widget step = XtVaCreateManagedWidget("step", commandWidgetClass, ctrlbox, NULL); Widget some = XtVaCreateManagedWidget("some", commandWidgetClass, ctrlbox, NULL); Widget evolve = XtVaCreateManagedWidget("evolve", commandWidgetClass, ctrlbox, NULL); XtAddCallback(rewind, XtNcallback, ResetCB, (XtPointer)ga); XtAddCallback(stop, XtNcallback, StopCB, (XtPointer)ga); XtAddCallback(step, XtNcallback, StepCB, (XtPointer)ga); XtAddCallback(some, XtNcallback, EvolveSomeCB, (XtPointer)ga); XtAddCallback(evolve, XtNcallback, EvolveCB, (XtPointer)ga); Widget quit = XtVaCreateManagedWidget("quit", commandWidgetClass, ctrlbox, NULL); XtAddCallback(quit, XtNcallback, QuitCB, (XtPointer)0); return toplevel; } #endif galib247/examples/makefile0100644003643600364360000000354410573535500014755 0ustar mwallmwall# -*- Mode: makefile -*- # Copyright (c) 1999 Matthew Wall, all rights reserved # ----------------------------------------------------------------------------- # To make all of the examples, do 'make'. You can compile any one of # the examples by typing 'make exN' where N is the number of the example you # want to compile. See the README for a description of what each example does. # ----------------------------------------------------------------------------- include ../makevars # Set these paths to the location of the GA library and headers. #GA_INC_DIR= /usr/local/include #GA_LIB_DIR= /usr/local/lib GA_INC_DIR= .. GA_LIB_DIR= ../ga INC_DIRS= -I$(GA_INC_DIR) LIB_DIRS= -L$(GA_LIB_DIR) EXS=randtest\ ex1 ex2 ex3 ex4 ex5 ex6 ex7 ex8 ex9\ ex10 ex11 ex12 ex13 ex14 ex15 ex16 ex17 ex18\ ex19 ex20 ex21 ex22 ex23 ex24 ex25 ex26 ex27 .SUFFIXES: .C .C.o: $(CXX) $(CXXFLAGS) $(INC_DIRS) -c $< all: $(EXS) # Use this for non-gnu make #$(EXS): $$@.o # $(CXX) $@.o -o $@ $(LIB_DIRS) -lga -lm $(CXX_LIBS) # Use this for gnu make $(EXS): %: %.o $(CXX) $@.o -o $@ $(LIB_DIRS) -lga -lm $(CXX_LIBS) clean: $(RM) $(EXS) $(RM) *.o *~ *.bak *.pixie core $(RM) test_results.txt test_stats.txt $(RM) *.dat $(RM) *.out *.exe vc* *.pdb test: $(EXS) $(RM) test_results.txt test_stats.txt @echo "running tests. this could take up to 1/2 hour, depending on" @echo "the speed of your computer. monitor test_results.txt and" @echo "test_stats.txt to see what is happening." @echo "" @rm -f test_results.txt @echo `uname -a` > test_stats.txt @echo "" >> test_stats.txt for x in $(EXS); do \ echo "$$x... "; \ echo "$$x" >> test_stats.txt; \ echo "start: " `date` >> test_stats.txt; \ ./$$x seed 555 >> test_results.txt; \ echo "finish: " `date` >> test_stats.txt; \ echo "" >> test_stats.txt; \ done galib247/examples/makefile.bcc0100644003643600364360000000330510573535500015476 0ustar mwallmwall# -*- Mode: makefile -*- # Copyright (c) 1999-2005 Matthew Wall, all rights reserved # ----------------------------------------------------------------------------- # To make all of the examples, do 'make'. You can compile any one of # the examples by typing 'make exN' where N is the number of the example you # want to compile. See the README for a description of what each example does. # ----------------------------------------------------------------------------- !include ../makevars.bcc GA_LIB=$(LIB_NAME).lib # Set these paths to the location of the GA library and headers. #GA_INC_DIR= /usr/local/include #GA_LIB_DIR= /usr/local/lib GA_INC_DIR= .. GA_LIB_DIR= ..\ga INC_DIRS= -I$(GA_INC_DIR) LIB_DIRS= -L$(GA_LIB_DIR) -L$(CXX_LIB_DIR) CXXFLAGS= $(CXXFLAGS) $(INC_DIRS) EXECS=randtest.exe\ ex1.exe ex2.exe ex3.exe ex4.exe ex5.exe ex6.exe ex7.exe ex8.exe ex9.exe\ ex10.exe ex11.exe ex12.exe ex13.exe ex14.exe ex15.exe ex16.exe ex17.exe ex18.exe\ ex19.exe ex20.exe ex21.exe ex22.exe ex23.exe ex24.exe ex25.exe ex26.exe ex27.exe all: $(EXECS) .SUFFIXES: .SUFFIXES: .obj .obj.exe: $(CXX) -q $(LIB_DIRS) $*.obj $(GA_LIB) clean: $(RM) test_results.txt test_stats.txt $(RM) *.dat $(RM) *.exe $(RM) *.tds $(RM) *.obj DATESTAMP=echo exit | cmd /q /k prompt $$D $$T test: $(EXECS) @echo running tests. this could take up to 1/2 hour, depending on @echo the speed of your computer. monitor test_results.txt and @echo test_stats.txt to see what is happening. @echo results > test_results.txt @echo stats > test_stats.txt @for %x in ( $(EXECS) ) do \ @echo %x & echo %x >> test_stats.txt & $(DATESTAMP) >> test_stats.txt & %x seed 555 >> test_results.txt & $(DATESTAMP) >> test_stats.txt galib247/examples/makefile.vcpp0100644003643600364360000000330710573535500015721 0ustar mwallmwall# -*- Mode: makefile -*- # Copyright (c) 1999-2005 Matthew Wall, all rights reserved # ----------------------------------------------------------------------------- # To make all of the examples, do 'make'. You can compile any one of # the examples by typing 'make exN' where N is the number of the example you # want to compile. See the README for a description of what each example does. # ----------------------------------------------------------------------------- !include ../makevars.vcpp GA_LIB=$(LIB_NAME).lib # Set these paths to the location of the GA library and headers. #GA_INC_DIR= /usr/local/include #GA_LIB_DIR= /usr/local/lib GA_INC_DIR= .. GA_LIB_DIR= ..\ga INC_DIRS= /I$(GA_INC_DIR) LIB_DIRS= /LIBPATH:$(GA_LIB_DIR) CXXFLAGS= $(CXXFLAGS) $(INC_DIRS) EXECS=randtest.exe\ ex1.exe ex2.exe ex3.exe ex4.exe ex5.exe ex6.exe ex7.exe ex8.exe ex9.exe\ ex10.exe ex11.exe ex12.exe ex13.exe ex14.exe ex15.exe ex16.exe ex17.exe ex18.exe\ ex19.exe ex20.exe ex21.exe ex22.exe ex23.exe ex24.exe ex25.exe ex26.exe ex27.exe all: $(EXECS) $(EXECS): $*.o $(LD) $(LDFLAGS) $*.o /out:$*.exe $(LIB_DIRS) $(GA_LIB) clean: $(RM) test_results.txt test_stats.txt $(RM) *.dat $(RM) *.exe $(RM) *.pdb $(RM) *.o $(RM) vc* DATESTAMP=echo exit | cmd /q /k prompt $$D $$T test: $(EXECS) @echo running tests. this could take up to 1/2 hour, depending on @echo the speed of your computer. monitor test_results.txt and @echo test_stats.txt to see what is happening. @echo results > test_results.txt @echo stats > test_stats.txt @for %%x in ( $(EXECS) ) do \ @echo %%x && echo %%x >> test_stats.txt && $(DATESTAMP) >> test_stats.txt && %%x seed 555 >> test_results.txt && $(DATESTAMP) >> test_stats.txt galib247/examples/pvmind/0040755003643600364360000000000010573536000014543 5ustar mwallmwallgalib247/examples/pvmind/genome.C0100644003643600364360000002500310573535477016137 0ustar mwallmwall/* ---------------------------------------------------------------------------- genome.C mbwall 5dec95 Copyright (c) 1995-1996 Massachusetts Institute of Technology DESCRIPTION: This file contains the information needed to evaluate an operate on a genome in these examples. ---------------------------------------------------------------------------- */ #include #include #include "genome.h" int id2idx(int tid, PVMData& data) { int idx = -1; for(int i=0; inreq]; int done = 0, outstanding = 0, next = 0; int bufid, status, bytes, msgtag, tid, who; while(!done) { // If we have a genome that needs to be initialized and one of the slaves is // available, then ask the slave to configure a genome and send us back the // configured, initialized genome. if(next < pop.size() && (bufid=pvm_nrecv(-1, MSG_READY)) != 0) { if(bufid > 0) { status = pvm_bufinfo(bufid, &bytes, &msgtag, &tid); status = SendGenomeInitialize(pop.individual(next), tid); if(status >= 0) { if((who = id2idx(tid, *data)) >= 0) { index[who] = next; next++; outstanding++; } else { cerr << "PopInit: bogus tid mapping: " << tid << "\n"; } } else { cerr << "PopInit: error sending initialize command to: " << tid; cerr << " genome " << next << " will be inited by next slave\n"; cerr << " error code is: " << status << "\n"; } } else { cerr << "PopInit: error from pvm_nrecv: " << bufid << "\n"; } } // If we have requests for initialization outstanding and a slave has posted // a message stating that it will provide genome data, then get the data from // the slave and stuff it into the appropriate genome in the population. if(outstanding > 0 && (bufid=pvm_nrecv(-1, MSG_GENOME_DATA)) != 0) { if(bufid > 0) { status = pvm_bufinfo(bufid, &bytes, &msgtag, &tid); if((who = id2idx(tid, *data)) >= 0) { if(index[who] >= 0) { status = RecvGenomeData(pop.individual(index[who])); if(status >= 0) { index[who] = -1; outstanding--; } else { cerr << "PopInit: error receiving data from: " << tid; cerr << " error code is: " << status << "\n"; } } else { cerr << "PopInit: index conflict from tid " << tid << "\n"; } } else { cerr << "PopInit: bogus tid mapping: " << tid << "\n"; } } else { cerr << "PopInit: error from pvm_nrecv: " << bufid << "\n"; } } if(next == pop.size() && outstanding == 0) done = 1; if(next > pop.size()) { cerr << "bogus value for next: " << next; cerr << " popsize is: " << pop.size() << "\n"; } } delete [] index; } // This population evaluator is the administrator for the parallelization. // It looks around to see when slaves are available to evaluate a genome. As // soon as a slave is available and a genome needs to be evaluated, this // routine sends it off. When a slave is finished, it posts a message to // say so and this routine gets the message and grabs the results from the // slave that posted the message. // An index of -1 means that the slave has no assignment. The first int in // the stream of stuff is always the ID of the slave (0-nslaves) that is // sending the information. After that it is either nothing (the slave just // reported that it is ready for another genome) or it is a float (the score // of the genome that was assigned to the slave). void PopulationEvaluator(GAPopulation& pop) { PVMDataPtr data = (PVMDataPtr)pop.userData(); int* index = new int [data->nreq]; int done = 0, outstanding = 0, next = 0; int bufid, status, bytes, msgtag, tid, who; while(!done) { // If we have a genome that needs to be evaluated and one of the slaves is // ready to evaluate it, send the genome to the slave. if(next < pop.size() && (bufid=pvm_nrecv(-1, MSG_READY)) != 0) { if(bufid > 0) { pvm_bufinfo(bufid, &bytes, &msgtag, &tid); status = SendGenomeData(pop.individual(next), tid); if(status >= 0) { if((who = id2idx(tid, *data)) >= 0) { index[who] = next; next++; outstanding++; } else { cerr << "PopEval: bogus tid mapping: " << tid << "\n"; } } else { cerr << "PopEval: error sending data to: " << tid; cerr << " error code is: " << status << "\n"; } } else { cerr << "PopEval: error from pvm_nrecv: " << bufid << "\n"; } } // If we have any genomes waiting for their evaluation and any slaves have // posted a message stating that they have a finished score ready for us, get // the score from the slave and stuff it into the appropriate genome. if(outstanding > 0 && (bufid=pvm_nrecv(-1, MSG_GENOME_SCORE)) != 0) { if(bufid > 0) { pvm_bufinfo(bufid, &bytes, &msgtag, &tid); if((who = id2idx(tid, *data)) >= 0) { if(index[who] >= 0) { status = RecvGenomeScore(pop.individual(index[who])); if(status >= 0) { index[who] = -1; outstanding--; } else { cerr << "PopEval: error receiving score from: " << tid; cerr << " error code is: " << status << "\n"; } } else { cerr << "PopEval: index conflict from tid " << tid << "\n"; } } else { cerr << "PopEval: bogus tid mapping: " << tid << "\n"; } } else { cerr << "PopEval: error from pvm_nrecv: " << bufid << "\n"; } } if(next == pop.size() && outstanding == 0) done = 1; if(next > pop.size()) { cerr << "bogus value for next: " << next; cerr << " popsize is: " << pop.size() << "\n"; } } delete [] index; } galib247/examples/pvmind/genome.h0100644003643600364360000000226610573535477016212 0ustar mwallmwall/* ---------------------------------------------------------------------------- genome.h mbwall 5dec95 Copyright (c) 1995-1996 Massachusetts Institute of Technology DESCRIPTION: This file contains the information needed to evaluate an operate on a genome in these examples. ---------------------------------------------------------------------------- */ #ifndef _genome_h_ #define _genome_h_ #include float GenomeEvaluator(GAGenome&); void GenomeInitializer(GAGenome&); void PopulationInitializer(GAPopulation&); void PopulationEvaluator(GAPopulation&); int SendGenomeData(GAGenome&, int); int RecvGenomeData(GAGenome&); int SendGenomeScore(GAGenome&, int); int RecvGenomeScore(GAGenome&); int SendGenomeInitialize(GAGenome&, int); int RecvGenomeInitialize(GAGenome&); int SendReady(int); typedef struct _PVMData { int masterid; int* tid; // task ids of all slave processes int ntasks; // number of slave tasks that are running int nreq; // number of tasks that we asked for } PVMData, *PVMDataPtr, **PVMDataHdl; const int MSG_READY=10; const int MSG_DONE=100; const int MSG_GENOME_DATA=50; const int MSG_GENOME_SCORE=51; const int MSG_GENOME_INITIALIZE=52; #endif galib247/examples/pvmind/Makefile.aimk0100644003643600364360000000352110573535477017142 0ustar mwallmwall# makefile for compiling the PVM example for GAlib # Copyright (c) 1995-1996 Massachusetts Institute of Technology # mbwall 5dec95 # # This makefile is designed to be used with aimk (that comes with pvm3). You # should set the PVM_ROOT and PVM_ARCH environment variables as described in # the PVM documentation. For our configuration, I have set them like this: # # setenv PVM_ROOT= /usr/local/pvm3 # setenv PVM_ARCH= `$PVM_ROOT/lib/pvmgetarch` # # (I do this in my .cshrc file) Your mileage may vary. You can 'hardcode' # the directories here in the makefile if you like, but then you won't be able # to compile on different architectures without changing this file. XDIR is # the location of your PVM binaries. Do a simple 'aimk' first, then, if # everything went OK, do 'aimk install' and that will move the binaries to your # PVM executables directory. When you use aimk it will create a subdirectory # in the current directory for each architecture on which you try to compile. SDIR= .. BDIR= $(HOME)/pvm3/bin XDIR= $(BDIR)/$(PVM_ARCH) VPATH= $(SDIR) GA_INC_DIR=$(SDIR)/../.. GA_LIB_DIR=$(SDIR)/../../ga INC_DIRS= -I$(SDIR)/. -I$(GA_INC_DIR) -I${PVM_ROOT}/include LIB_DIRS= -L$(SDIR)/. -L$(GA_LIB_DIR) -L${PVM_ROOT}/lib/${PVM_ARCH} LIBS= -lpvm3 -lga -lm CCFLAGS= +w +pp -O -g $(INC_DIRS) C++C= DCC SRCS= master.C slave.C genome.C all: master slave master.o: $(SDIR)/master.C $(C++C) $(CCFLAGS) -c $(SDIR)/master.C slave.o: $(SDIR)/slave.C $(C++C) $(CCFLAGS) -c $(SDIR)/slave.C genome.o: $(SDIR)/genome.C $(C++C) $(CCFLAGS) -c $(SDIR)/genome.C master: $$@.o genome.o $(C++C) $@.o genome.o -o $@ $(LIB_DIRS) $(LIBS) slave: $$@.o genome.o $(C++C) $@.o genome.o -o $@ $(LIB_DIRS) $(LIBS) install: master slave $(XDIR) mv master slave $(XDIR) $(XDIR): - mkdir $(BDIR) $(XDIR) clean: rm -rf *~ *.bak *.out *.o core master slave ii_files galib247/examples/pvmind/master.C0100644003643600364360000001330610573535477016163 0ustar mwallmwall/* ---------------------------------------------------------------------------- master.C mbwall 5dec95 Copyright (c) 1995-1996 Massachusetts Institute of Technology DESCRIPTION: Example program to illustrate use of GAlib with PVM. This example uses a master-slave configuration to parallelize the genetic algorithm. In this case, the master controls the evolution and farms out the task of evaluating single genomes to each of the slaves. Initialization of each genome is also distributed (in case you have a CPU-intensive initializer). This method of parallelization is effective only if the length of time it takes to evaluate a genome is longer than the time it takes to transmit the genome data from the master to the slave. If this is not the case then try the single population per processor version of parallelization. Be careful about mixing and matching parallel implementations and various GAlib components - they do *not* all interoperate as you might expect. For example, many of the default GAlib methods do a fair amount of caching, so if you parallelize one component without doing all the others, you might end up slowing everything down. ---------------------------------------------------------------------------- */ #include #include #include #include #include #include "genome.h" #define SLAVE_NAME "slave" // name of the compiled slave program int StartupPVM(const char*, PVMData&); int ShutdownPVM(PVMData&); int main(int argc, char** argv) { cout << "This program tries to fill a 1DBinaryStringGenome with\n"; cout << "alternating 1s and 0s using a simple genetic algorithm. It runs\n"; cout << "in parallel using PVM.\n\n"; cout.flush(); GAParameterList params; GASimpleGA::registerDefaultParameters(params); params.set(gaNpopulationSize, 150); params.set(gaNnGenerations, 100); params.set(gaNscoreFilename, "bog.dat"); params.set(gaNflushFrequency, 10); params.set(gaNscoreFrequency, 1); params.parse(argc, argv); int usepvm = 1; int length = 32; PVMData data; // our own PVM data structure used by pops data.nreq = 5; // by default we want this many slaves to run for(int i=1; i= argc){ cerr << argv[0] << ": genome length needs a value.\n"; exit(1); } else{ length = atoi(argv[i]); continue; } } else if(strcmp("nslaves", argv[i]) == 0 || strcmp("ns", argv[i]) == 0){ if(++i >= argc){ cerr << argv[0] << ": number of slaves needs a value.\n"; exit(1); } else{ data.nreq = atoi(argv[i]); continue; } } else { cerr << argv[0] << ": unrecognized arguement: " << argv[i] << "\n\n"; cerr << "valid arguements include standard GAlib arguments plus:\n"; cerr << " nopvm\t\tdo not use pvm\n"; cerr << " nslaves n\tnumber of slave processes (" << data.nreq << ")\n"; cerr << " len l\t\tlength of bit string (" << length << ")\n"; cerr << "\n"; exit(1); } } if(usepvm && StartupPVM(argv[0], data)) exit(1); GA1DBinaryStringGenome genome(length, GenomeEvaluator); GAPopulation pop(genome,1); if(usepvm){ pop.initializer(PopulationInitializer); pop.evaluator(PopulationEvaluator); pop.userData((void*)&data); } GASimpleGA ga(pop); ga.parameters(params); time_t tmStart = time(NULL); cout << "initializing the GA...\n"; cout.flush(); ga.initialize(); cout << "evolving the solution "; cout.flush(); while(!ga.done()){ ga.step(); if(ga.generation() % 10 == 0){ cout << ga.generation() << " "; cout.flush(); } } ga.flushScores(); time_t tmFinish = time(NULL); genome = ga.statistics().bestIndividual(); cout << "\nThe evolution took " << tmFinish-tmStart << " seconds.\n"; cout << "The GA found an individual with a score of "< #include "genome.h" int main(int argc, char** argv) { if(argc > 1) { cerr << "\n" << argv[0] << ": This program takes no arguments.\n"; exit(1); } int mytid = pvm_mytid(); int masterid = pvm_parent(); if(mytid < 0 || masterid < 0) { cerr << "\n" << argv[0] << ": Couldn't get slave/master IDs. Aborting.\n"; exit(1); } // create the genome (we'll resize it later on) GARandomSeed(); GA1DBinaryStringGenome genome(1); genome.evaluator(GenomeEvaluator); genome.initializer(GenomeInitializer); // send an "I'm ready" message then wait for instructions from the master SendReady(masterid); int done = 0; int status, bufid, bytes, msgtag, tid; while(!done){ bufid = pvm_recv(masterid, -1); if(bufid >= 0) { status = pvm_bufinfo(bufid, &bytes, &msgtag, &tid); if(msgtag == MSG_DONE) { done = 1; } else if(msgtag == MSG_GENOME_DATA) { RecvGenomeData(genome); SendGenomeScore(genome, masterid); SendReady(masterid); } else if(msgtag == MSG_GENOME_INITIALIZE) { RecvGenomeInitialize(genome); SendGenomeData(genome, masterid); SendReady(masterid); } else { cerr << argv[0] << ": unknown msgtag: " << msgtag << "\n"; } } else { cerr << argv[0] << ": error from pvm_recv: " << bufid << "\n"; } } pvm_exit(); return 0; } galib247/examples/pvmpop/0040755003643600364360000000000010573536000014567 5ustar mwallmwallgalib247/examples/pvmpop/genome.C0100644003643600364360000001500110573535477016160 0ustar mwallmwall/* ---------------------------------------------------------------------------- genome.C mbwall 5dec95 Copyright (c) 1995-1996 Massachusetts Institute of Technology DESCRIPTION: This file contains the information needed to evaluate an operate on a genome in these examples. We define routines for sending and receiving genome data as well as routines for modifying the genetic algorithm's population. At some point we should add better error checking to the pvm status returns. ---------------------------------------------------------------------------- */ #include #include #include "genome.h" // When this flag is defined, the initialize and evaluate function dump a // string to cerr that tells which host they're running on. You can then look // at this info in the pvm log file. //#define DEBUG int PackIndividual(GAGenome& g); int UnpackIndividual(GAGenome& g); // The first few routines depend on the type of genome that you are using. // If you want to change the genome type, be sure to modify these functions. // Technically these should be member functions of a genome class that knows // how to pack and unpack itself. Perhaps some other day... // This is a simple one-max-like objective function. We just try to set every // other bit in the binary string. float GenomeEvaluator(GAGenome& g) { GA1DBinaryStringGenome& genome = (GA1DBinaryStringGenome&)g; #ifdef DEBUG char buf[255]; gethostname(buf, 255); cerr << "evaluating on " << buf << "\n"; #endif float score=0.0; for(int i=0; i=0; i++) status = PackIndividual(pop.individual(i)); status = pvm_send(toid, MSG_INCOMING_POPULATION); return status; } // This assumes that the original population contains at least one individual // from which to grow. If it does not, the data in the buffer will be ignored. int RecvPopulation(GAPopulation& pop) { int status = 0; int psize = 0; status = pvm_upkint(&psize, 1, 1); pop.size(psize); for(int i=0; i=0; i++) status = UnpackIndividual(pop.individual(i)); return status; } int SendStatistics(int toid, const GAStatistics& s) { int status = 0; unsigned long int val; val = s.numsel; status = pvm_pkulong(&val, 1, 1); val = s.numcro; status = pvm_pkulong(&val, 1, 1); val = s.nummut; status = pvm_pkulong(&val, 1, 1); val = s.numrep; status = pvm_pkulong(&val, 1, 1); val = s.numeval; status = pvm_pkulong(&val, 1, 1); val = s.numpeval; status = pvm_pkulong(&val, 1, 1); status = pvm_send(toid, MSG_INCOMING_STATISTICS); return status; } int RecvStatistics(GAStatistics& s) { int status = 0; unsigned long int val; status = pvm_upkulong(&val, 1, 1); s.numsel = val; status = pvm_upkulong(&val, 1, 1); s.numcro = val; status = pvm_upkulong(&val, 1, 1); s.nummut = val; status = pvm_upkulong(&val, 1, 1); s.numrep = val; status = pvm_upkulong(&val, 1, 1); s.numeval = val; status = pvm_upkulong(&val, 1, 1); s.numpeval = val; return status; } // Send the specified number of individuals from the current population to // the specified task. int SendMigration(int toid, GAGeneticAlgorithm& ga, int count) { int status = 0; status = pvm_initsend(PvmDataDefault); status = pvm_pkint(&count, 1, 1); for(int i=0; i=0; i++) status = PackIndividual(ga.population().best(i)); status = pvm_send(toid, MSG_INCOMING_MIGRATION); return status; } // Receive a bunch of individuals from a task. To do this, we clone the GA's // population, stuff the immigrants into the population, trash the worst // individuals to bring the population size back down to what it was, then // stick the population back into the GA. // This implementation is really inefficient, but you get the idea of how // to do this... int RecvMigration(GAGeneticAlgorithm& ga) { int status = 0; GAPopulation pop(ga.population()); GAGenome *tmpind = ga.population().individual(0).clone(); int count = 0; status = pvm_upkint(&count, 1, 1); for(int i=0; i=0; i++) { status = UnpackIndividual(*tmpind); pop.add(*tmpind); } for(int j=0; j #include #define GENOME_LENGTH 64 float GenomeEvaluator(GAGenome&); int RecvMigration(GAGeneticAlgorithm& ga); int SendMigration(int toid, GAGeneticAlgorithm& ga, int count); int RecvPopulation(GAPopulation&); int SendPopulation(int toid, const GAPopulation&); int RecvStatistics(GAStatistics&); int SendStatistics(int toid, const GAStatistics&); const int MSG_DONE =1; const int MSG_INITIALIZE =2; const int MSG_STEP =3; const int MSG_RECEIVE_MIGRATION =4; const int MSG_SEND_MIGRATION =5; const int MSG_SEND_POPULATION =6; const int MSG_SEND_STATISTICS =7; const int MSG_INCOMING_MIGRATION =8; const int MSG_INCOMING_POPULATION =9; const int MSG_INCOMING_STATISTICS =10; const int MSG_STEP_COMPLETE =11; const int MSG_SET_POPULATION_SIZE =12; const int MSG_READY =100; #endif galib247/examples/pvmpop/Makefile.aimk0100644003643600364360000000363610573535477017175 0ustar mwallmwall# makefile for compiling the PVM example for GAlib # Copyright (c) 1995-1996 Massachusetts Institute of Technology # mbwall 5dec95 # # This makefile is designed to be used with aimk (that comes with pvm3). You # should set the PVM_ROOT and PVM_ARCH environment variables as described in # the PVM documentation. For our configuration, I have set them like this: # # setenv PVM_ROOT= /usr/local/pvm3 # setenv PVM_ARCH= `$PVM_ROOT/lib/pvmgetarch` # # (I do this in my .cshrc file) Your mileage may vary. You can 'hardcode' # the directories here in the makefile if you like, but then you won't be able # to compile on different architectures without changing this file. XDIR is # the location of your PVM binaries. Do a simple 'aimk' first, then, if # everything went OK, do 'aimk install' and that will move the binaries to your # PVM executables directory. When you use aimk it will create a subdirectory # in the current directory for each architecture on which you try to compile. SDIR= .. BDIR= $(HOME)/pvm3/bin XDIR= $(BDIR)/$(PVM_ARCH) VPATH= $(SDIR) CC_INC_DIR=/usr/include/CC INC_DIRS= -I$(SDIR)/. -I$(SDIR)/../.. -I${PVM_ROOT}/include LIB_DIRS= -L$(SDIR)/. -L$(SDIR)/../../ga -L${PVM_ROOT}/lib/${PVM_ARCH} LIBS= -lpvm3 -lga -lm CCFLAGS= +w +pp -O -g $(INC_DIRS) C++C= DCC SRCS= master.C slave.C genome.C all: master slave master.o: $(SDIR)/master.C $(C++C) $(CCFLAGS) -c $(SDIR)/master.C slave.o: $(SDIR)/slave.C $(C++C) $(CCFLAGS) -c $(SDIR)/slave.C genome.o: $(SDIR)/genome.C $(C++C) $(CCFLAGS) -c $(SDIR)/genome.C PVMDemeGA.o: $(SDIR)/PVMDemeGA.C $(C++C) $(CCFLAGS) -c $(SDIR)/PVMDemeGA.C master: $$@.o genome.o PVMDemeGA.o $(C++C) $@.o genome.o PVMDemeGA.o -o $@ $(LIB_DIRS) $(LIBS) slave: $$@.o genome.o $(C++C) $@.o genome.o -o $@ $(LIB_DIRS) $(LIBS) install: master slave $(XDIR) mv master slave $(XDIR) $(XDIR): - mkdir $(BDIR) $(XDIR) clean: rm -rf *~ *.bak *.out *.o core master slave ii_files galib247/examples/pvmpop/master.C0100644003643600364360000000264510573535477016213 0ustar mwallmwall/* ---------------------------------------------------------------------------- master.C mbwall 5dec95 Copyright (c) 1995-1996 Massachusetts Institute of Technology DESCRIPTION: Example program to illustrate use of GAlib with PVM. This example uses a master-slave configuration to parallelize the genetic algorithm. In this case, the master controls the evolution by specifying migrations between populations on various processes. ---------------------------------------------------------------------------- */ #include #include #include "PVMDemeGA.h" #include "genome.h" int main(int argc, char** argv) { cout << "This program tries to fill a 1DBinaryStringGenome with\n"; cout << "alternating 1s and 0s using a simple genetic algorithm. It runs\n"; cout << "in parallel using PVM and a population on each process.\n\n"; cout.flush(); GA1DBinaryStringGenome genome(GENOME_LENGTH); PVMDemeGA ga(genome); ga.parameters(argc, argv); ga.parameters("settings.txt"); if(ga.spawn("slave") < 0) exit(1); cout << "initializing..." << endl; ga.initialize(); cout << ga.statistics().bestIndividual() << endl; cout << "evolving..." << endl; while(!ga.done()){ ga.step(); cout << ga.statistics().bestIndividual() << endl; } ga.flushScores(); cout << "\nThe GA found an individual with a score of "; cout << ga.statistics().bestIndividual().score() << endl; return 0; } galib247/examples/pvmpop/PVMDemeGA.C0100644003643600364360000002230710573535477016362 0ustar mwallmwall/* ---------------------------------------------------------------------------- DemeGA.C mbwall 28jul94 Copyright (c) 1995-1996 Massachusetts Institute of Technology all rights reserved Souce file for the deme-based genetic algorithm object. ---------------------------------------------------------------------------- */ #include #include #include "PVMDemeGA.h" #include "genome.h" #define DEBUG PVMDemeGA::PVMDemeGA(const GAGenome& c) : GADemeGA(c) { _status = 0; _Ntid = _ntid = _nhosts = _narch = 0; _tid = 0; _mid = 0; } PVMDemeGA::PVMDemeGA(const GAPopulation& p) : GADemeGA(p) { _status = 0; _Ntid = _ntid = _nhosts = _narch = 0; _tid = 0; _mid = 0; } PVMDemeGA::PVMDemeGA(const PVMDemeGA& orig) : GADemeGA(orig) { _status = 0; _Ntid = _ntid = _nhosts = _narch = 0; _tid = 0; _mid = 0; copy(orig); } PVMDemeGA::~PVMDemeGA(){ reap(); // just in case } PVMDemeGA& PVMDemeGA::operator=(const PVMDemeGA& orig){ if(&orig != this) copy(orig); return *this; } void PVMDemeGA::copy(const GAGeneticAlgorithm& g){ reap(); // need to fix this behavior GADemeGA::copy(g); } /* int GADemeGA::populationSize(int i, unsigned int value){ if(value < 1){ GAErr(className(), "populationSize", gaErrBadPopSize); value = 1; } if(i == ALL) for(unsigned int ii=0; iisize(value); else deme[i]->size(value); if(_mid) { for(int j=0; j<_ntid; j++) { int psize = deme[j]->size(); _status = pvm_pkint(&psize, 1, 1); _status = pvm_send(_tid[j], MSG_SET_POPULATION_SIZE); } } return value; } */ // To initialize this genetic algorithm, we make sure all of our spawns are // not evolving then we tell them all to initialize themselves. Then we wait // and copy their populations into our own. Update our stats based upon the // harvested populations. void PVMDemeGA::initialize(unsigned int seed) { GARandomSeed(seed); if(_mid == 0) return; #ifdef DEBUG cerr << "sending initialize command to slaves...\n"; #endif for(int j=0; j<_ntid; j++) { _status = pvm_initsend(PvmDataDefault); _status = pvm_send(_tid[j], MSG_INITIALIZE); } collect(); for(int i=0; i<_ntid; i++) { pstats[i].reset(*deme[i]); pop->individual(i).copy(deme[i]->best()); } pop->touch(); stats.reset(*pop); } // To evolve the genetic algorithm, we loop through all of our populations and // tell each process to evolve its population for a certain number of // generations. Then allow the migrator to do its thing. Each process is // supposed to keep track of the statistics for its population, so we reap // those as well. void PVMDemeGA::step() { if(_mid == 0) return; #ifdef DEBUG cerr << "sending step command to slaves...\n"; #endif for(int j=0; j<_ntid; j++) { int nsteps = 10; _status = pvm_initsend(PvmDataDefault); _status = pvm_pkint(&nsteps, 1, 1); _status = pvm_send(_tid[j], MSG_STEP); } #ifdef DEBUG cerr << "waiting for slaves to step...\n"; #endif int flag = _ntid; while(flag > 0) { int bufid = pvm_recv(-1, -1); if(bufid >= 0) { int bytes, msgtag, tid; _status = pvm_bufinfo(bufid, &bytes, &msgtag, &tid); switch(msgtag) { case MSG_STEP_COMPLETE: flag--; #ifdef DEBUG cerr << " tid " << tid << " has finished step\n"; #endif break; default: cerr << className() << ": step:\n"; cerr << " unexpected msgtag: " << msgtag << "\n"; break; } } else { cerr << className() << ": step:\n"; cerr << " error from pvm_recv: " << bufid << "\n"; } } migrate(); // Now update the statistics and individuals in our local populations. We copy // all of the distributed individuals into our own populations then do the // statistics updates. Since we copy, we don't force any new evaluations. If // you don't need to keep the master up-to-date, then comment out this section // and just let the slaves run on their own. collect(); for(unsigned int jj=0; jjindividual(kk).copy(deme[kk]->best()); stats.numsel += pstats[kk].numsel; stats.numcro += pstats[kk].numcro; stats.nummut += pstats[kk].nummut; stats.numrep += pstats[kk].numrep; stats.numeval += pstats[kk].numeval; } pop->touch(); stats.update(*pop); for(unsigned int ll=0; llsize()); _status = pvm_initsend(PvmDataDefault); _status = pvm_pkint(&toid, 1, 1); _status = pvm_pkint(&count, 1, 1); _status = pvm_send(fromid, MSG_SEND_MIGRATION); #ifdef DEBUG cerr << "told task " << fromid; cerr << " to migrate " << count << " individuals to task " << toid << "\n"; #endif } // Gather the population data from each of our distributed populations. int PVMDemeGA::collect() { #ifdef DEBUG cerr << "sending request for populations...\n"; #endif for(int j=0; j<_ntid; j++) { _status = pvm_initsend(PvmDataDefault); _status = pvm_send(_tid[j], MSG_SEND_POPULATION); } #ifdef DEBUG cerr << "waiting for populations from slaves...\n"; #endif int flag = _ntid; while(flag > 0) { int bufid = pvm_recv(-1, -1); if(bufid >= 0) { int bytes, msgtag, tid; _status = pvm_bufinfo(bufid, &bytes, &msgtag, &tid); int which = tid2idx(tid); switch(msgtag) { case MSG_INCOMING_POPULATION: _status = RecvPopulation(*deme[which]); flag--; #ifdef DEBUG cerr << " received pop from tid " << tid << " (" << which << ")\n"; #endif break; default: cerr << className() << ": collect:\n"; cerr << " unexpected msgtag: " << msgtag << "\n"; break; } } else { cerr << className() << ": collect:\n"; cerr << " error from pvm_recv: " << bufid << "\n"; } } return _status; } // Hook up to the pvm and spawn the slave processes. int PVMDemeGA::spawn(const char* slavename) { _mid = pvm_mytid(); if(_mid < 0) { cerr << "\n" << className() << ": spawn:\n"; cerr << " Bad ID for master task. Have you started the PVM?\n"; return _status = _mid; } struct pvmhostinfo* hostp; _status = pvm_config(&_nhosts, &_narch, &hostp); if(_status == PvmSysErr) { cerr << "\n" << className() << ": spawn:\n"; cerr << " PVM not responding. Have you started the PVM?\n"; return _status; } _Ntid = npop; _tid = new int [_Ntid]; // task IDs for the slaves char sn[32]; // PVM is not const-safe... strcpy(sn, slavename); _ntid = pvm_spawn(sn, (char**)0, 0, "", _Ntid, _tid); if(_ntid <= 0) { cerr << className() << ": spawn:\n Error spawning slaves.\n"; cerr << " Error codes of failed spawns are:\n"; for(int i=0; i<_Ntid; i++) { cerr << " slave "; cerr.width(3); cerr< 0) { int bufid = pvm_recv(-1, -1); if(bufid >= 0) { int bytes, msgtag, tid; _status = pvm_bufinfo(bufid, &bytes, &msgtag, &tid); int which = tid2idx(tid); switch(msgtag) { case MSG_READY: #ifdef DEBUG cerr << " slave " << tid << " (" << which << ") is alive\n"; #endif flag--; break; default: cerr << className() << ": spawn:\n"; cerr << " unexpected msgtag: " << msgtag << "\n"; break; } } else { cerr << className() << ": spawn:\n"; cerr << " error from pvm_recv: " << bufid << "\n"; } } #ifdef DEBUG cerr << "slaves appear to be up and running.\n"; #endif return _status; } // Reap all of our spawned processes and detach ourselves from the PVM. void PVMDemeGA::reap() { for(int j=0; j<_Ntid; j++) if(_tid[j] > 0) pvm_kill(_tid[j]); delete [] _tid; _tid = 0; _ntid = _Ntid = 0; if(_mid > 0) pvm_exit(); _mid = 0; } int PVMDemeGA::tid2idx(int taskid) const { int idx = -1; for(int i=0; i<_ntid && idx == -1; i++) if(taskid == _tid[i]) idx = i; return idx; } galib247/examples/pvmpop/PVMDemeGA.h0100644003643600364360000000502510573535477016425 0ustar mwallmwall/* ---------------------------------------------------------------------------- PVMDemeGA.h mbwall jan96 Copyright (c) 1995-1996 Massachusetts Institute of Technology all rights reserved Header for the deme (parallel population) genetic algorithm class. This genetic algorithm lets you specify a number of individuals to migrate from one population to another at the end of each generation. You can specify how many populations to maintain. Each population evolves using a steady-state genetic algorithm. At the end of each generation, the specified number of individuals migrate from one population to the next (we use the loop migration topology in this implementation). You can modify the migration method by deriving a new class from this one and redefine the migration method. If you want to use a different kind of genetic algorithm for each population then you'll have to modify the mechanics of the step method. ---------------------------------------------------------------------------- */ #ifndef _PVMDemeGA_h_ #define _PVMDemeGA_h_ #include #include class PVMDemeGA : public GADemeGA { public: GADefineIdentity("PVMDemeGA", 238); PVMDemeGA(const GAGenome&); PVMDemeGA(const GAPopulation&); PVMDemeGA(const PVMDemeGA&); PVMDemeGA& operator=(const PVMDemeGA&); virtual ~PVMDemeGA(); virtual void copy(const GAGeneticAlgorithm&); virtual void initialize(unsigned int seed=0); virtual void step(); virtual void migrate(); PVMDemeGA & operator++() { step(); return *this; } const GAPopulation& population(unsigned int i) const; const GAStatistics& statistics() const {return stats;} const GAStatistics& statistics(unsigned int i) const {return pstats[i];} public: int spawn(const char*); void reap(); int status() const { return _status; } protected: int _mid; // id of the master task int *_tid; // id of each slave task int _ntid, _Ntid; // how many we have, how many we requested int _status; // status of last pvm function called int _nhosts; // number of hosts we can see int _narch; // number of architectures we can see int tid2idx(int) const; int ntasks() const { return _ntid; } int nreq() const { return _Ntid; } int collect(); }; #ifndef NO_STREAMS inline ostream & operator<< (ostream & os, PVMDemeGA & arg) {arg.write(os); return(os);} inline istream & operator>> (istream & is, PVMDemeGA & arg) {arg.read(is); return(is);} #endif #endif galib247/examples/pvmpop/README0100644003643600364360000000732210573535477015471 0ustar mwallmwallmbw 5dec95 To build the programs in this directory, use aimk (part of the PVM package). You should be able to simply type 'aimk' to build the programs or 'aimk install' to build the programs then put them into your PVM bin directories. Be sure you edit the Makefile first to work with your compiler and to specify the location of the GAlib headers and library. You can use 'aimk clean' just as you would use 'make clean'. This example shows how to use GAlib with pvm to do parallel processing of your genetic algorithms. In this example we use a master-slave configuration. The master controls the overall evolution and the slaves chug away. Using PVM you can specify on which machines the slaves should run (see the PVM documentation for more details about that). Note that this configuration is particularly useful for problems in which the objective function takes a long time to run relative to the time it takes to transfer a single genome from the master to the slave (or vice versa). Before you run this example, you must install PVM3 (I have tested with version 3.3.10 - you'll have to check the PVM documentation for PVM incompatibilities). The makefile in this directory assumes that you have your environment properly configured as described in the PVM documentation (see the makefile for details) For more details about PVM, see http://www.netlib.org/pvm3/index.html http://www.epm.ornl.gov/pvm/pvm_home.html OK, so you don't want to chug through the PVM documentation? Here's the quick and dirty PVM config (assuming that PVM is on your system already): 1) add this to your .cshrc file (you may have to change the value of PVM_ROOT to match your system's configuration) # ----------------------------------------------------------------------------- # pvm additions for .cshrc file (mbw dec95) # # These are for using the parallel virtual machine codes. The first tells # where PVM is located, the second tells where XPVM is located. setenv PVM_ROOT /nfs/lancet/local/pvm3 setenv XPVM_ROOT /nfs/lancet/local/pvm3/xpvm # These set up the environment so we can find the pvm man pages and run pvm # programs without typing in the explicit path to each executable. setenv PVM_ARCH `$PVM_ROOT/lib/pvmgetarch` set path=($path $PVM_ROOT/lib) set path=($path $PVM_ROOT/bin/$PVM_ARCH $HOME/pvm3/bin/$PVM_ARCH) # The MANPATH variable must be defined already for this to work. setenv MANPATH ${MANPATH}:$PVM_ROOT/man # ----------------------------------------------------------------------------- 2) create a pvm directory for your programs cd mkdir pvm3 pvm3/bin 3) create a hosts file that defines your virtual machine - just put the hostnames of all the machines you'll be using into a file, then when you start pvm, pass the name of the hosts file and pvm will use those hosts to set up the PVM. I keep a file called ~/pvm3/hosts with my default host configuration. 4) start pvm pvm ~/pvm3/hosts 5) run your program in a separate shell (do not type this at the pvm prompt) master ngen 100 nslaves 25 6) to shut down pvm, type 'halt' at the pvm prompt (if you just type 'quit' then you'll leave the pvm prompt but pvmd will still be running) IMPORTANT NOTES To shut down all of the processes spawned in your PVM, type 'reset' at the pvm prompt. If you just control-C the master then it will die but the slaves will continue to run (unless you do some signal handling in the master). Don't forget to 'halt' the PVM when you are finished running everything. For help with PVM commands, type 'help' at the PVM prompt. To see the cout/cerr messages from your spawned (slave) processes, look in the file /var/tmp/pvml.XXXXXX where XXXXXX is your uid. On some systems the pvm log file may be located in /tmp/pvml.XXXXXX galib247/examples/pvmpop/settings.txt0100644003643600364360000000104610573535477017207 0ustar mwallmwall# sample settings for GAlib applications # GAlib expects parameters in name-value pairs. The name should be a single # string (no whitespace allowed). The value should be of a type appropriate # for the named parameter. Anything after a # character will be ignored. # The file must end with a blank line. number_of_populations 10 population_size 50 mutation_probability 0.01 crossover_probability 1.0 score_filename bog.dat score_frequency 1 flush_frequency 10 select_scores 7 # 1=mean, 2=max, 4=min, 8=dev, 16=div number_of_generations 50 galib247/examples/pvmpop/slave.C0100644003643600364360000000531610573535477016030 0ustar mwallmwall/* ---------------------------------------------------------------------------- slave.C mbwall 5dec95 Copyright (c) 1995-1996 Massachusetts Institute of Technology DESCRIPTION: Each slave evolves its own population. Between steps it checks to see if any messages have appeared for it. After each step it sends a message that says that it has completed a generation. A slave can receive two kinds of messages, one to send individuals (and where to send them), and another to receive them (and from where to receive them). The master controls the migrations by telling the slaves when and where to migrate individuals. To control the actual migration algorithm, you can modify the section of code that merges the received individuals into the population. You can also determine which individuals will be selected to migrate to another population. ---------------------------------------------------------------------------- */ #include #include #include "genome.h" int main(int, char** argv) { int status = 0; int mytid = pvm_mytid(); int masterid = pvm_parent(); if(mytid < 0 || masterid < 0) { cerr << "\n" << argv[0] << ": Couldn't get slave/master IDs. Aborting.\n"; exit(1); } GA1DBinaryStringGenome genome(GENOME_LENGTH,GenomeEvaluator); GASteadyStateGA ga(genome); status = pvm_initsend(PvmDataDefault); status = pvm_send(masterid, MSG_READY); int done = 0; while(!done){ int bufid = pvm_recv(-1, -1); int ival; if(bufid >= 0) { int bytes, msgtag, tid; status = pvm_bufinfo(bufid, &bytes, &msgtag, &tid); switch(msgtag) { case MSG_DONE: done = 1; break; case MSG_SET_POPULATION_SIZE: ival = gaDefPopSize; status = pvm_upkint(&ival, 1, 1); ga.populationSize(ival); break; case MSG_INITIALIZE: ga.initialize(); break; case MSG_STEP: ival = 0; status = pvm_upkint(&ival, 1, 1); for(int i=0; i #include #include #include #define cout STD_COUT #define cerr STD_CERR static const int HIST_SIZE=501; static const int NFLIPS=10000; static const long int NUM_CHECKS=1000000L; static const int RCHI=100; int main(int argc, char **argv) { cerr << "This program checks the random number generators in GAlib.\n"; cerr << "These are not rigorous statistical tests, but they should\n"; cerr << "give you a quick indication of whether or not the library is\n"; cerr << "working properly. Command-line options include:\n\n"; cerr << " [+-]chi - do the chi square test (default)\n"; cerr << " [+-]hist - do the histogram tests. Histograms should be\n"; cerr << " nearlyflat, i.e. each number has an equal chance\n"; cerr << " of beingchosen.\n"; cerr << " [+-]bnds - do the bounds tests. All numbers generated\n"; cerr << " should be within the limits specified in the\n"; cerr << " test.\n"; cerr << " [+-]means - do the means tests. A few thousand invocations\n"; cerr << " of each random number function are made, and the\n"; cerr << " averages of these calls are displayed with the\n"; cerr << " number that should have been found.\n"; cerr << " seed n - specify the seed number to use for the RNG. You\n"; cerr << " should get the same results every time if you\n"; cerr << " specify the same seed every time. A seed of 0\n"; cerr << " tells the lib to pick its own seed based upon the\n"; cerr << " current time.\n"; cerr << "\n"; cerr.flush(); int dohist = 0; int dobnds = 0; int domeans = 0; int dochisq = 1; int seed = 0; int i; for(i=1; i= argc) { cerr << "You must enter a number when specifying a random seed.\n"; exit(1); } else { seed = atoi(argv[i]); } } else if(strcmp("+chi", argv[i]) == 0){ dochisq = 1; } else if(strcmp("-chi", argv[i]) == 0){ dochisq = 0; } else if(strcmp("+hist", argv[i]) == 0){ dohist = 1; } else if(strcmp("-hist", argv[i]) == 0){ dohist = 0; } else if(strcmp("+bnds", argv[i]) == 0){ dobnds = 1; } else if(strcmp("-bnds", argv[i]) == 0){ dobnds = 0; } else if(strcmp("+means", argv[i]) == 0){ domeans = 1; } else if(strcmp("-means", argv[i]) == 0){ domeans = 0; } } // Tell us which RNG we're using... cout << argv[0] << ": Random Number Test\n"; cout << "Using the " << GAGetRNG() << " random number generator (RNG).\n"; // initialize the RNG by calling the seed routine with our seed if(seed) { cout << "Using specified random seed " << seed << "\n"; } else { cout << "No random seed specified\n"; } GARandomSeed(seed); unsigned int libseed = GAGetRandomSeed(); cout << "Library thinks the random seed is " << libseed << "\n"; // the basic chi square test for randomness of a RNG // must do it more than once since it might be wrong about one in ten // times. The error is r*t/N - N and should be within 2*sqrt(r) of r. if(dochisq) { cout << "\n"; cerr << "chi-square test...\n"; cout << "running the chi-square test for randomness of the RNG...\n"; cout << " (there will be some failures of the chi-square test)\n"; int ii; double elimit = 2*sqrt((double)RCHI); double chisq = 0.0; long int NCHI=1000; // NCHI should be >= 10 * RCHI long int f[RCHI]; cerr << " integer test (" << NCHI << ")...\n"; cout << " integer test (" << NCHI << "): chi-squared should be within "; cout << elimit << " of " << RCHI << "\n"; cout.flush(); for(ii=0; ii<10; ii++) { memset(f, 0, RCHI * sizeof(long int)); for(i=0; i elimit) cout << "***failed***"; cout << "\n"; } cout.flush(); NCHI = 10000; cerr << " integer test (" << NCHI << ")...\n"; cout << " integer test (" << NCHI << "): chi-squared should be within "; cout << elimit << " of " << RCHI << "\n"; cout.flush(); for(ii=0; ii<10; ii++) { memset(f, 0, RCHI * sizeof(long int)); long int i; long int t; for(i=0; i elimit) cout << "***failed***"; cout << "\n"; } cout.flush(); NCHI = 10000; cerr << " integer test (" << NCHI << ")...\n"; cout << " integer test (" << NCHI << "): chi-squared should be within "; cout << elimit << " of " << RCHI << "\n"; cout.flush(); for(ii=0; ii<10; ii++) { memset(f, 0, RCHI * sizeof(long int)); long int i; long int t; for(i=0; i elimit) cout << "***failed***"; cout << "\n"; } cout.flush(); NCHI = 100000; cerr << " integer test (" << NCHI << ")...\n"; cout << " integer test (" << NCHI << "): chi-squared should be within "; cout << elimit << " of " << RCHI << "\n"; cout.flush(); for(ii=0; ii<10; ii++) { memset(f, 0, RCHI * sizeof(long int)); long int i; long int t; for(i=0; i elimit) cout << "***failed***"; cout << "\n"; } cout.flush(); } // histograms of the tests if(dohist) { cout << "\n"; cerr << "histograms...\n"; cout << "plotting histograms of calls to random number functions...\n"; int i, j, histogram[HIST_SIZE]; memset(histogram, 0, HIST_SIZE*sizeof(int)); cout << "\n100 random integers in [0, 1] with GARandomInt():\n"; for(i=0; i<100; i++) histogram[GARandomInt()]++; for(i=0; i<=1; i++){ cout << i << "\t"; for(j=0; j 5){ err += 1; } } if(err) cout << " " << err << " values out of bounds.\n"; else cout << "ok\n"; cout.flush(); cerr << " " << NUM_CHECKS << " GARandomInt(0,3)...\n"; cout << "GARandomInt(0,3) ..."; cout.flush(); err = 0; for(ii=0; ii 3){ err += 1; } } if(err) cout << " " << err << " values out of bounds.\n"; else cout << "ok\n"; cout.flush(); cerr << " " << NUM_CHECKS << " GARandomInt(200,255)...\n"; cout << "GARandomInt(200,255) ..."; cout.flush(); err = 0; for(ii=0; ii 255){ err += 1; } } if(err) cout << " " << err << " values out of bounds.\n"; else cout << "ok\n"; cout.flush(); float valf, lastf=0.0; cerr << " " << NUM_CHECKS << " GARandomFloat(-10,5)...\n"; cout << "GARandomFloat(-10,5) ..."; cout.flush(); for(ii=0; ii 5){ err += 1; lastf = valf; } } if(err) cout << " " << err << " values out of bounds (" << lastf << ").\n"; else cout << "ok\n"; cout.flush(); cerr << " " << NUM_CHECKS << " GARandomFloat(0,3)...\n"; cout << "GARandomFloat(0,3) ..."; cout.flush(); err = 0; for(ii=0; ii 3){ err += 1; lastf = valf; } } if(err) cout << " " << err << " values out of bounds (" << lastf << ").\n"; else cout << "ok\n"; cout.flush(); cerr << " " << NUM_CHECKS << " GARandomFloat(200,255)...\n"; cout << "GARandomFloat(200,255) ..."; cout.flush(); err = 0; for(ii=0; ii 255){ err += 1; lastf = valf; } } if(err) cout << " " << err << " values out of bounds (" << lastf << ").\n"; else cout << "ok\n"; cout.flush(); double vald, lastd=0.0; cerr << " " << NUM_CHECKS << " GARandomDouble(-10,5)...\n"; cout << "GARandomDouble(-10,5) ..."; cout.flush(); for(ii=0; ii 5){ err += 1; lastd = vald; } } if(err) cout << " " << err << " values out of bounds (" << lastd << ").\n"; else cout << "ok\n"; cout.flush(); cerr << " " << NUM_CHECKS << " GARandomDouble(0,3)...\n"; cout << "GARandomDouble(0,3) ..."; cout.flush(); err = 0; for(ii=0; ii 3){ err += 1; lastd = vald; } } if(err) cout << " " << err << " values out of bounds (" << lastd << ").\n"; else cout << "ok\n"; cout.flush(); cerr << " " << NUM_CHECKS << " GARandomDouble(200,255)...\n"; cout << "GARandomDouble(200,255) ..."; cout.flush(); err = 0; for(ii=0; ii 255){ err += 1; lastd = vald; } } if(err) cout << " " << err << " values out of bounds (" << lastd << ").\n"; else cout << "ok\n"; cout.flush(); } return 0; } galib247/examples/README.txt0100644003643600364360000002776110573535500014762 0ustar mwallmwallGAlib examples mbw 5jan96 How to compile the examples ------------------------------------------------------------------------------- Copy the contents of this directory into your own filespace. In the new directory, edit the makefile as needed to specify the location of the GAlib headers and library. If you system supports makedepend, do 'make depend' to update the makefile dependencies. To build all of the examples, type 'make all' or simply 'make'. To build a specific example, type 'make exN' where N is the number of the example you want to build. For example, to build example 5 you would type 'make ex5'. To remove old core, executable, object, and data files, do 'make clean'. You only need to do 'make depend' when the dependencies change. For example, if you modify one of the examples so that it uses routines in another file, you will have to modify the makefile then do 'make depend' so that make will know about the new dependency. What the examples do ------------------------------------------------------------------------------- ex1 Fill a 2DBinaryStringChromosome with alternating 0s and 1s using a SimpleGA. ex2 Generate a sequence of random numbers, then use a Bin2DecChromosome and SimpleGA to try and match the sequence. This example shows how to use the user-data member of genomes in objective functions. ex3 Read a 2D pattern from a data file then try to match the pattern using a 2DBinaryStringChromosome and a SimpleGA. This example also shows how to use the GAParametes object for setting genetic algorithm parameters and reading command-line arguments. ex4 Fill a 3DBinaryStringChromosome with alternating 0s and 1s using a SteadyStateGA. This example uses many member functions of the genetic algorithm to control which statistics are recorded and dumped to file. ex5 This example shows how to build a composite genome (a cell?) using a 2DBinaryStringGenome and a Bin2DecGenome. The composite genome uses behaviors that are defined in each of the genomes that it contains. The objective is to match a pattern and sequence of numbers. ex6 Grow a GATreeGenome using a SteadyStateGA. This example illustrates the use of specialized methods to override the default initialization method and to specialize the output from a tree. It also shows how to use templatized genome classes. Finally, it shows the use of the parameters object to set default values then allow these to be modified from the command line. The objective function in this example tries to grow the tree as large as possible. ex7 Identical in function to example 3, this example shows how to use the increment operator (++), completion measure, and other member functions of the GA. It uses a GA with overlapping populations rather than the non-overlapping GA in example 3 and illustrates the use of many of the GA member functions. It also illustrates the use of the parameter list for reading settings from a file, and shows how to stuff a genome with data from an input stream. ex8 Grow a GAListGenome using a GA with overlapping populations. This shows how to randomly initialize a list of integers, how to use the sigma truncation scaling object to handle objective scores that may be positive or negative, and the 'set' member of the genetic algorithm for controlling statistics and other genetic algorithm parameters. ex9 Find the maximum value of a continuous function in two variables. This example uses a GABin2DecGenome and simple GA. It also illustrates how to use the GASigmaTruncationScaling object (rather than the default linear scaling). Sigma truncation is particularly useful for objective functions that return negative values. ex10 Find the maximum value of a continuous, periodic function. This example illustrates the use of sharing to do speciation. It defines a sample distance function (one that does the distance measure based on the genotype, the other based on phenotype). It uses a binary- to-decimal genome to represent the function values. ex11 Generate a sequence of descending numbers using an order-based list. This example illustrates the use of a GAListGenome as an order-based chromosome. It contains a custom initializer and shows how to use this custom initializer in the List genome. ex12 Alphabetize a sequence of characters. Similar to example 11, this example illustrates the use of the GAStringGenome (rather than a list) as an order-based chromosome. ex13 This program runs a GA-within-GA. The outer level GA tries to match the pattern read in from a file. The inner GA tries to match a sequence of randomly generated numbers (the sequence is generated at the beginning of the program's execution). The inner level GA is run only when the outer GA reaches a threshhold objective score. ex14 Another illustration of how to use composite chromosomes. In this example, the composite chromosome contains a user-specifiable number of lists. Each list behaves differently and is not affected by mutations, crossovers, or initializations of the other lists. ex15 The completion function of a GA determines when it is "done". This example uses the convergence to tell when the GA has reached the optimum (the default completion measure is number-of-generations). It uses a binary-to-decimal genome and tries to match a sequence of randomly generated numbers. ex16 Tree chromosomes can contain any kind of object in the nodes. This example shows how to put a point object into the nodes of a tree to represent a 3D plant. The objective function tries to maximize the size of the plant. ex17 Array chromsomes can be used when you need tri-valued alleles. This example uses a 2D array with trinary alleles. ex18 This example compares the performance of three different genetic algorithms. The genome and objective function are those used in example 3, but this example lets you specify which type of GA you want to use to solve the problem. You can use steady state, simple, or incremental just by specifying one of them on the command line. The example saves the generational data to file so that you can then plot the convergence data to see how the performance of each genetic algorithm compares to the others. ex19 The 5 DeJong test problems. ex20 Holland's royal road function. This example computes Holland's 1993 ICGA version of the Royal Road problem. Holland posed this problem as a challenge to test the performance of genetic algorithms and challenged other GA users to match or beat his performance. ex21 This example illustrates various uses of the allele set in array genomes. The allele set may be an enumerated list of items or a bounded range of continuous values, or a bounded set of discrete values. This example shows how each of these may be used in combination with a real number genome. ex22 This example shows how to derive a new genetic algorithm class in order to customize the replacement method. Here we derive a new type of steady-state genetic algorithm in which speciation is done more effectively by not only scaling fitness values but also by controlling the way new individuals are inserted into the population. ex23 The genetic algorithm object can either maximize or minimize your objective function. This example shows how to use the minimize abilities of the genetic algorithm. It uses a real number genome with one element to find the maximum or minimum of a sinusoid. ex24 This example shows how to restricted mating using a custom genetic algorithm and custom selection scheme. The restricted mating in the genetic algorithm tries to pick individuals that are similar (based upon their comparator). The selector chooses only the upper half of the population (so it cannot choose very bad individuals, unlike the roulette wheel selector, for example). ex25 Multiple populations on a single CPU. This example uses its own genetic algorithm class called a 'DemeGA'. The genetic algorithm controls the migration behavior for moving individuals between populations. ex26 Travelling Salesperson Problem. Although genetic algorithms are not the best way to solve the TSP, we include an example of how it can be done. This example uses an order-based list as the genome to figure out the shortest path that connects a bunch of towns such that each town is visited exactly once. It uses the edge recombination crossover operator (you can try it with the partial match crossover as well to see how poorly PMX does on this particular problem). ex27 Deterministic crowding. Although the algorithms built-in to GAlib allow you to do quite a bit of customization, sometimes you'll want to derive your own class so that you can really tweak the way the algorithm works. This example shows one way of implementing the deterministic crowding method by deriving an entirely new genetic algorithm class. randtest Use this program to verify that the random number generator is generating suitably random numbers on your machine. This is by no means a comprehensive random number test suite, but it will give you some idea of how well GAlib's random number generator is working. graphic (available only in the UNIX distribution) You can learn a great deal by watching the genetic algorithm evolve. This directory contains two examples that show populations of solutions evolving in real time. Both programs use X resources as well as command-line arguments to control their behavior. You can also use a standard GAlib settings file. The programs will compile with either the Motif or athena widget set. The first example has a simple X windows interface that lets you start, stop, restart, and incrementally evolve a population of indivdiuals. The objective function is a continuous function in two variables with concentric rings and a maximal value located in the center. You can see the evolution in action, so it becomes very obvious if your operators are not working correctly or if the algorithm is converging prematurely. You can choose between 3 different genetic algorithms, 2 different genomes (real or binary-to-decimal), and 4 different functions. The second example shows solutions to the travelling salesman problem evolving in real time. You can compare three different algorithms: simple, steady-state, and deterministic crowding. gnu (available only in the UNIX distribution) This directory contains the code for an example that uses the BitString object from the GNU class library. The example illustrates how to incorporate an existing object (in this case the BitString) into a GAlib Genome type. The gnu directory contains the source code needed for the BitString object (taken from the GNU library) plus the two files (bitstr.h and bitstr.C) needed to define the new genome type and the example file that runs the GA (gnuex.C). pvmind (available only in the UNIX distribution) This directory contains code that illustrates how to use GAlib with PVM in a master-slave configuration wherein the master process is the genetic algorithm with a single population and each slave process is a genome evaluator. The master sends individual genomes to the slave processes to be evaluated then the slaves return the evaluations. pvmpop (available only in the UNIX distribution) This directory contains code that illustrates a PVM implementation of parallel populations. The master process initiates a cluster of slaves each of which contains a single population. The master process harvests individuals from all of the distributed populations. With a few modifications you can also use this example with the deme GA from example 25 (it uses migration to distribute diversity between pops). galib247/examples/results/0040755003643600364360000000000010573536000014747 5ustar mwallmwallgalib247/examples/results/test_results-aix.txt0100644003643600364360000006575210573535476021063 0ustar mwallmwall./randtest: Random Number Test Using the RAN2 random number generator (RNG). Using specified random seed 555 Library thinks the random seed is 555 running the chi-square test for randomness of the RNG... (there will be some failures of the chi-square test) integer test (1000): chi-squared should be within 20 of 100 run #0 93.2 run #1 101.52 run #2 119.752 run #3 103.175 run #4 130.718 ***failed*** run #5 118.672 run #6 93.8672 run #7 101.787 run #8 132.579 ***failed*** run #9 114.258 integer test (10000): chi-squared should be within 20 of 100 run #0 88.2 run #1 87.82 run #2 77.3 ***failed*** run #3 81.22 run #4 94.18 run #5 113.46 run #6 102.72 run #7 94.24 run #8 71.24 ***failed*** run #9 117.86 integer test (10000): chi-squared should be within 20 of 100 run #0 109.12 run #1 113.06 run #2 133.26 ***failed*** run #3 99.82 run #4 109.18 run #5 90.52 run #6 100.58 run #7 101.34 run #8 93.74 run #9 89.38 integer test (100000): chi-squared should be within 20 of 100 run #0 119.2 run #1 99.978 run #2 110.9 run #3 103.678 run #4 82.366 run #5 102.464 run #6 91.632 run #7 86.788 run #8 109.812 run #9 86.968 Example 1 This program tries to fill a 2DBinaryStringGenome with alternating 1s and 0s using a SimpleGA The GA found: 0101010101 1010101010 0101010101 1010101010 0101010101 Example 2 This program generates a sequence of random numbers then uses a simple GA and binary-to-decimal genome to match the sequence. input sequence: 0.265886 54.6261 3 -2.85019 69151.2 0.00150462 2 random values in the genome: 0.980392 18.4314 3 -4.34118 23997.6 0.00276471 0.494118 the ga generated: 0.278431 54.5098 3 -2.87059 2450.59 0.00163529 2.00392 best of generation data are in 'bog.dat' Example 3 This program reads in a data file then runs a simple GA whose objective function tries to match the pattern of bits that are in the data file. input pattern: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * best of generation data are in 'bog.dat' the ga generated: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Example 4 This program tries to fill a 3DBinaryStringGenome with alternating 1s and 0s using a SteadyStateGA the ga generated: 0101010101 1010101010 0101010101 1010101010 0101010101 1010101010 0101010101 1010101010 0101010101 1010101010 0101010101 1010101010 0101010101 1010101010 0101010101 best of generation data are in 'bog.dat' Example 5 This program shows how to use a composite genome. It reads a matrix from a data file and a set of values to be matched in a binary-to-decimal genome then uses a steady-state GA to match the pattern and value set. input pattern: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * input sequence: 10.2 32.5 66 99.234 0.003 210 the ga generated: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 8.3767 32.4286 55.2418 101.924 0.00209011 150.615 Example 6 This example uses a SteadyState GA and Tree genome. It tries to maximize the size of the tree genomes that it contains. The genomes contain ints in its nodes. 8653 nodes, 120 levels deep. best of generation data are in 'bog.dat' Example 7 This program reads in a data file then runs a steady-state GA whose objective function tries to match the pattern of bits that are in the data file. input pattern: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * the ga generated: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * best of generation data are in 'bog.dat' Example 8 This program runs a steady-state GA whose objective function tries to maximize the size of the list and tries to make lists that contain the number 101 in the nodes. The lists contain ints in the nodes. the list contains 0 nodes the ga used the parameters: minimaxi 1 number_of_generations 50 generations_to_convergence 20 convergence_percentage 0.99 crossover_probability 0.6 mutation_probability 0.05 population_size 40 score_frequency 1 flush_frequency 10 record_diversity 0 score_filename bog.dat select_scores 7 number_of_best 1 replacement_percentage 0.5 replacement_number 20 Example 9 This program finds the maximum value in the function y = - x1^2 - x2^2 with the constraints -5 <= x1 <= 5 -5 <= x2 <= 5 the ga found an optimum at the point (7.62951e-05, 0.00328069) best of generation data are in 'bog.dat' Example 10 This program uses sharing to do speciation. The objective function has more than one optimum, so different genomes may have equally high scores. Speciation keeps the population from clustering at one optimum. Both gene-wise and phenotype-wise distance functions are used. Populations from all three runs are written to the files pop.nospec.dat, pop.genespec.dat and pop.phenespec.dat. The function is written to the file sinusoid.dat running with no speciation (fitness proportionate scaling)... the ga found an optimum at the point 3.2549 running the ga with speciation (sharing using bit-wise)... the ga found an optimum at the point 2.2549 running the ga with speciation (sharing using phenotype-wise)... the ga found an optimum at the point 4.2549 dumping the function to file... Example 11 This program illustrates the use of order-based lists. The list in this problem contains 25 numbers, 0 to 24. It tries to put them in descending order from 24 to 0. the ga generated the following list (objective score is 24): 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 best of generation data are in 'bog.dat' minimaxi 1 number_of_generations 1000 generations_to_convergence 20 convergence_percentage 0.99 crossover_probability 0.6 mutation_probability 0.01 population_size 30 score_frequency 10 flush_frequency 10 record_diversity 0 score_filename bog.dat select_scores 2 number_of_best 1 replacement_percentage 0.5 replacement_number 15 Example 12 This program illustrates the use of order-based strings. The string in this problem contains 26 letters, a to z. It tries to put them in alphabetic order. the ga generated the following string (objective score is 26): abcdefghijklmnopqrstuvwxyz GAStringGenome Example 13 This program runs a GA-within-GA. The outer level GA tries to match the pattern read in from a file. The inner level GA is run only when the outer GA reaches a threshhold objective score then it tries to match a sequence of numbers that were generated randomly at the beginning of the program's execution. You might have to run the primary GA for more than 5000 generations to get a score high enough to kick in the secondary genetic algorithm. Use the ngen option to do this on the command line. input pattern: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * input sequence: 0.265886 54.6261 3 -2.85019 69151.2 0.00150462 2 the ga generated: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 0.411765 12.9412 3 -2.16471 74143.5 0.00749412 6.17647 best of generation data are in 'bog.dat' Example 14 This example shows how to create a genome that contains a list of lists. We create a composite genome that has lists in it. Each list has some nodes, only one of which contains the number 0. The objective is to move the node with number 0 in it to the nth position where n is the number of the list within the composite genome. a randomly-generated set of paths: list 0: 28 20 21 22 25 24 0 26 23 27 list 1: 22 20 23 21 0 24 25 26 28 27 list 2: 20 23 21 28 27 24 22 26 0 25 list 3: 0 20 21 22 23 24 27 26 25 28 list 4: 0 28 21 22 23 24 27 26 20 25 list 5: 28 27 21 26 23 24 25 22 20 0 the ga generated: list 0: 0 26 24 22 25 23 27 28 21 20 list 1: 24 0 20 26 23 22 25 27 21 28 list 2: 21 26 0 22 23 20 25 27 28 24 list 3: 24 21 22 0 23 27 25 20 26 28 list 4: 24 26 23 21 0 20 22 28 27 25 list 5: 20 26 21 25 23 0 24 22 27 28 Example 15 This program generates a sequence of random numbers then uses a simple GA and binary-to-decimal genome to match the sequence. It uses the convergence of the best-of-generation as the criterion for when to stop. input sequence: 0.265886 54.6261 3 -2.85019 69151.2 0.00150462 2 random values in the genome: 0.419608 85.098 3 -4.90588 6760 0.00834118 5.92941 the ga generated: 0.247059 49.8039 3 -2.74118 60823.5 0.00156471 2.00392 Example 16 This example uses a SteadyState GA and Tree genome. It tries to maximize the size of the tree genomes that it contains. The genomes contain points in its nodes. Two different runs are made: first with the swap subtree mutator, second with the destructive mutator. initializing...evolving for 10 generations............. the ga generated a tree with 37 nodes, 9 levels deep. initializing...evolving for 10 generations............. the ga generated a tree with 35 nodes, 12 levels deep. Example 17 This program illustrates the use of a 2DArrayGenome with three alleles. It tries to fill a 2D array with alternating 0s and 1s, and -1s at the corners. You will have to run it for something like 10000 generations to get the perfect score. evolving........................................................................................................................................................................................................... the ga generated: -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 Example 18 This program is designed to compare the GA types. You can specify steady-state, incremental, or simple GA and tweak any of the parameters for each of these GA types. The objective function tries to match a pattern read in from a file. input pattern: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * the ga generated: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * the statistics for the run are: 400 # current generation 0.990521 # current convergence 12000 # number of selections since initialization 10776 # number of crossovers since initialization 2707 # number of mutations since initialization 12000 # number of replacements since initialization 11051 # number of genome evaluations since initialization 201 # number of population evaluations since initialization 211 # maximum score since initialization 88 # minimum score since initialization 182.65 # average of all scores ('on-line' performance) 187.255 # average of maximum scores ('off-line' performance) 178.162 # average of minimum scores ('off-line' performance) 112.9 # mean score in initial population 127 # maximum score in initial population 88 # minimum score in initial population 7.63996 # standard deviation of initial population -1 # diversity of initial population (0=identical,-1=unset) 207.2 # mean score in current population 211 # maximum score in current population 203 # minimum score in current population 2.49689 # standard deviation of current population -1 # diversity of current population (0=identical,-1=unset) 20 # how far back to look for convergence 10 # how often to record scores 50 # how often to write scores to file bog.dat # name of file to which scores are written the objective function was called 11051 times best of generation data are in 'bog.dat' Example 19 This program runs the DeJong test problems. running DeJong function number 1 ... the ga generated: 5.11 -5.12 -5.12 the statistics for the run are: 400 # current generation 1 # current convergence 3200 # number of selections since initialization 2481 # number of crossovers since initialization 152 # number of mutations since initialization 2800 # number of replacements since initialization 2524 # number of genome evaluations since initialization 401 # number of population evaluations since initialization 78.5409 # maximum score since initialization 0.342654 # minimum score since initialization 77.4228 # average of all scores ('on-line' performance) 78.006 # average of maximum scores ('off-line' performance) 77.0203 # average of minimum scores ('off-line' performance) 25.943 # mean score in initial population 76.0281 # maximum score in initial population 0.342654 # minimum score in initial population 14.6341 # standard deviation of initial population -1 # diversity of initial population (0=identical,-1=unset) 78.5409 # mean score in current population 78.5409 # maximum score in current population 78.5409 # minimum score in current population 7.75982e-06 # standard deviation of current population -1 # diversity of current population (0=identical,-1=unset) 20 # how far back to look for convergence 10 # how often to record scores 50 # how often to write scores to file bog.dat # name of file to which scores are written best-of-generation data are in 'bog.dat' Example 20 Running Holland's Royal Road test problem with a genome that is 240 bits long (16 blocks). The parameters are as follows: block size: 8 gap size: 7 m*: 4 u*: 1 u: 0.3 v: 0.02 the ga generated: 110010100110101111111110100011010111000001101111111110010111011000111001011110001010011100111111111000101111111110110001100110011010111011110000011011011000110101000111111110111000101000111111001111111110011001001110010111101111111110101000 the highest level achieved was 1 the statistics for the run are: 10000 # current generation 1 # current convergence 2560000 # number of selections since initialization 2305756 # number of crossovers since initialization 613723 # number of mutations since initialization 2560000 # number of replacements since initialization 2360486 # number of genome evaluations since initialization 10001 # number of population evaluations since initialization 4.52 # maximum score since initialization -0.06 # minimum score since initialization 4.51608 # average of all scores ('on-line' performance) 4.51795 # average of maximum scores ('off-line' performance) 4.51532 # average of minimum scores ('off-line' performance) 0.541289 # mean score in initial population 1.9 # maximum score in initial population -0.06 # minimum score in initial population 0.303989 # standard deviation of initial population -1 # diversity of initial population (0=identical,-1=unset) 4.52001 # mean score in current population 4.52 # maximum score in current population 4.52 # minimum score in current population 1.38418e-05 # standard deviation of current population -1 # diversity of current population (0=identical,-1=unset) 20 # how far back to look for convergence 20 # how often to record scores 100 # how often to write scores to file bog.dat # name of file to which scores are written the parameters for the run are: minimaxi 1 number_of_generations 10000 generations_to_convergence 20 convergence_percentage 0.99 crossover_probability 0.9 mutation_probability 0.001 population_size 512 score_frequency 20 flush_frequency 100 record_diversity 0 score_filename bog.dat select_scores 2 number_of_best 1 replacement_percentage 0.5 replacement_number 256 Example 21 This example shows various uses of the allele set object in combination with the real number genome. running ga number 1 (alternate allele(0) and allele(3))... the ga generated: -10 10 -10 10 -10 10 -10 10 running ga number 2 (continuous descending order)... the ga generated: 0.722113 0.690404 0.475627 0.443254 0.413628 0.307699 0.286382 0.0776234 running ga number 2a (descending order, EXCLUSIVE)... the ga generated: 0.877096 0.635132 0.0272497 0.92776 0.512969 0.228361 0.17755 0.021867 running ga number 3 (discretized ascending order)... the ga generated: 2.5 3 4 4.5 6 7 9 9.5 running ga number 4 (maximize each gene)... the ga generated: 10 100 -5 -0.0001 11000 Example 22 This example shows how to derive your own genetic algorithm class. Here we use a custom, single-child crossover and a modified replacement strategy with overlapping populations. initializing... evolving.......... dumping the function to file... initial population is in 'pop.initial.dat' final population is in 'pop.final.dat' the function is in 'sinusoid.dat' parameters were: minimaxi 1 number_of_generations 500 generations_to_convergence 20 convergence_percentage 0.99 crossover_probability 1 mutation_probability 0.01 population_size 100 score_frequency 10 flush_frequency 100 record_diversity 0 score_filename bog.dat select_scores 255 number_of_best 1 replacement_percentage 0.25 replacement_number 25 Example 23 This program tries to maximize or minimize, depending on the command line argument that you give it. Use the command-line argument 'mm -1' to minimize (the default for this example), or 'mm 1' to maximize. The objective function is a simple sinusoidal. printing initial population to file... printing final population to file... printing function to file... Example 24 This example illustrates how to derive your own genetic algorithm. This genetic algorithm does restricted mating and uses a selector slightly more finicky than a uniform random selector. The objective function is a simple sinusoidal. printing population to file 'population.dat'... printing function to file 'sinusoid.dat'... Example 25 This example uses a genetic algorithm with multiple populations. initializing...evolving....................................................................................................... best individual is: 11111111111111111111111111111111 100 # current generation 1 # current convergence 13000 # number of selections since initialization 12500 # number of crossovers since initialization 12024 # number of mutations since initialization 12500 # number of replacements since initialization 12650 # number of genome evaluations since initialization 1005 # number of population evaluations since initialization 1 # maximum score since initialization 0 # minimum score since initialization 0.163021 # average of all scores ('on-line' performance) 0.984688 # average of maximum scores ('off-line' performance) 0 # average of minimum scores ('off-line' performance) 0.1125 # mean score in initial population 0.6875 # maximum score in initial population 0 # minimum score in initial population 0.255937 # standard deviation of initial population -1 # diversity of initial population (0=identical,-1=unset) 0.166667 # mean score in current population 1 # maximum score in current population 0 # minimum score in current population 0.379049 # standard deviation of current population -1 # diversity of current population (0=identical,-1=unset) 20 # how far back to look for convergence 1 # how often to record scores 0 # how often to write scores to file generations.dat # name of file to which scores are written Example 26 The Travelling Salesman Problem (TSP) demo program. initializing...evolving...10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 170 180 190 200 210 220 230 240 250 260 270 280 290 300 310 320 330 340 350 360 370 380 390 400 410 420 430 440 450 460 470 480 490 500 510 520 530 540 550 560 570 580 590 600 610 620 630 640 650 660 670 680 690 700 710 720 730 740 750 760 770 780 790 800 810 820 830 840 850 860 870 880 890 900 910 920 930 940 950 960 970 980 990 1000 the shortest path found is 22.6503 this is the distance from the sequence 5 6 10 14 18 19 15 11 7 3 2 1 20 0 4 8 12 16 17 13 9 1000 # current generation 1 # current convergence 100000 # number of selections since initialization 100000 # number of crossovers since initialization 10014 # number of mutations since initialization 100000 # number of replacements since initialization 100100 # number of genome evaluations since initialization 1001 # number of population evaluations since initialization 64.3227 # maximum score since initialization 22.6503 # minimum score since initialization 23.1626 # average of all scores ('on-line' performance) 23.2062 # average of maximum scores ('off-line' performance) 23.0545 # average of minimum scores ('off-line' performance) 54.0745 # mean score in initial population 64.3227 # maximum score in initial population 44.4397 # minimum score in initial population 4.07012 # standard deviation of initial population -1 # diversity of initial population (0=identical,-1=unset) 22.6503 # mean score in current population 22.6503 # maximum score in current population 22.6503 # minimum score in current population 2.66312e-06 # standard deviation of current population -1 # diversity of current population (0=identical,-1=unset) 20 # how far back to look for convergence 100 # how often to record scores 0 # how often to write scores to file generations.dat # name of file to which scores are written Example 27 Deterministic crowding demonstration program. In addition to the standard GAlib command-line arguments, you can specify one of the four following functions: 0 - modified Himmelblau's function 1 - Foxholes (25) 2 - Schwefel's nasty (1 glob. Max bei (420.96/420.96) 3 - Mexican Hat (optimum at 0,0) best individual is 3.00116 1.99599 100 # current generation 0.999999 # current convergence 10000 # number of selections since initialization 5000 # number of crossovers since initialization 245 # number of mutations since initialization 953 # number of replacements since initialization 5100 # number of genome evaluations since initialization 101 # number of population evaluations since initialization 10 # maximum score since initialization 5.06768 # minimum score since initialization 9.90808 # average of all scores ('on-line' performance) 9.99984 # average of maximum scores ('off-line' performance) 9.35657 # average of minimum scores ('off-line' performance) 8.84823 # mean score in initial population 9.99917 # maximum score in initial population 5.06768 # minimum score in initial population 1.05433 # standard deviation of initial population -1 # diversity of initial population (0=identical,-1=unset) 9.99484 # mean score in current population 10 # maximum score in current population 9.96593 # minimum score in current population 0.00755568 # standard deviation of current population -1 # diversity of current population (0=identical,-1=unset) 20 # how far back to look for convergence 100 # how often to record scores 0 # how often to write scores to file generations.dat # name of file to which scores are written galib247/examples/results/test_results-hpux11.txt0100644003643600364360000006575310573535476021431 0ustar mwallmwall./randtest: Random Number Test Using the RAN2 random number generator (RNG). Using specified random seed 555 Library thinks the random seed is 555 running the chi-square test for randomness of the RNG... (there will be some failures of the chi-square test) integer test (1000): chi-squared should be within 20 of 100 run #0 93.2 run #1 101.52 run #2 119.752 run #3 103.175 run #4 130.718 ***failed*** run #5 118.672 run #6 93.8672 run #7 101.787 run #8 132.579 ***failed*** run #9 114.258 integer test (10000): chi-squared should be within 20 of 100 run #0 88.2 run #1 87.82 run #2 77.3 ***failed*** run #3 81.22 run #4 94.18 run #5 113.46 run #6 102.72 run #7 94.24 run #8 71.24 ***failed*** run #9 117.86 integer test (10000): chi-squared should be within 20 of 100 run #0 109.12 run #1 113.06 run #2 133.26 ***failed*** run #3 99.82 run #4 109.18 run #5 90.52 run #6 100.58 run #7 101.34 run #8 93.74 run #9 89.38 integer test (100000): chi-squared should be within 20 of 100 run #0 119.2 run #1 99.978 run #2 110.9 run #3 103.678 run #4 82.366 run #5 102.464 run #6 91.632 run #7 86.788 run #8 109.812 run #9 86.968 Example 1 This program tries to fill a 2DBinaryStringGenome with alternating 1s and 0s using a SimpleGA The GA found: 0101010101 1010101010 0101010101 1010101010 0101010101 Example 2 This program generates a sequence of random numbers then uses a simple GA and binary-to-decimal genome to match the sequence. input sequence: 0.265886 54.6261 3 -2.85019 69151.2 0.00150462 2 random values in the genome: 0.980392 18.4314 3 -4.34118 23997.6 0.00276471 0.494118 the ga generated: 0.278431 54.5098 3 -2.87059 2450.59 0.00163529 2.00392 best of generation data are in 'bog.dat' Example 3 This program reads in a data file then runs a simple GA whose objective function tries to match the pattern of bits that are in the data file. input pattern: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * best of generation data are in 'bog.dat' the ga generated: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Example 4 This program tries to fill a 3DBinaryStringGenome with alternating 1s and 0s using a SteadyStateGA the ga generated: 0101010101 1010101010 0101010101 1010101010 0101010101 1010101010 0101010101 1010101010 0101010101 1010101010 0101010101 1010101010 0101010101 1010101010 0101010101 best of generation data are in 'bog.dat' Example 5 This program shows how to use a composite genome. It reads a matrix from a data file and a set of values to be matched in a binary-to-decimal genome then uses a steady-state GA to match the pattern and value set. input pattern: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * input sequence: 10.2 32.5 66 99.234 0.003 210 the ga generated: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 8.3767 32.4286 55.2418 101.924 0.00209011 150.615 Example 6 This example uses a SteadyState GA and Tree genome. It tries to maximize the size of the tree genomes that it contains. The genomes contain ints in its nodes. 8653 nodes, 120 levels deep. best of generation data are in 'bog.dat' Example 7 This program reads in a data file then runs a steady-state GA whose objective function tries to match the pattern of bits that are in the data file. input pattern: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * the ga generated: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * best of generation data are in 'bog.dat' Example 8 This program runs a steady-state GA whose objective function tries to maximize the size of the list and tries to make lists that contain the number 101 in the nodes. The lists contain ints in the nodes. the list contains 0 nodes the ga used the parameters: minimaxi 1 number_of_generations 50 generations_to_convergence 20 convergence_percentage 0.99 crossover_probability 0.6 mutation_probability 0.05 population_size 40 score_frequency 1 flush_frequency 10 record_diversity 0 score_filename bog.dat select_scores 7 number_of_best 1 replacement_percentage 0.5 replacement_number 20 Example 9 This program finds the maximum value in the function y = - x1^2 - x2^2 with the constraints -5 <= x1 <= 5 -5 <= x2 <= 5 the ga found an optimum at the point (7.62939e-05, 0.00328064) best of generation data are in 'bog.dat' Example 10 This program uses sharing to do speciation. The objective function has more than one optimum, so different genomes may have equally high scores. Speciation keeps the population from clustering at one optimum. Both gene-wise and phenotype-wise distance functions are used. Populations from all three runs are written to the files pop.nospec.dat, pop.genespec.dat and pop.phenespec.dat. The function is written to the file sinusoid.dat running with no speciation (fitness proportionate scaling)... the ga found an optimum at the point 3.2549 running the ga with speciation (sharing using bit-wise)... the ga found an optimum at the point 2.2549 running the ga with speciation (sharing using phenotype-wise)... the ga found an optimum at the point 4.2549 dumping the function to file... Example 11 This program illustrates the use of order-based lists. The list in this problem contains 25 numbers, 0 to 24. It tries to put them in descending order from 24 to 0. the ga generated the following list (objective score is 24): 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 best of generation data are in 'bog.dat' minimaxi 1 number_of_generations 1000 generations_to_convergence 20 convergence_percentage 0.99 crossover_probability 0.6 mutation_probability 0.01 population_size 30 score_frequency 10 flush_frequency 10 record_diversity 0 score_filename bog.dat select_scores 2 number_of_best 1 replacement_percentage 0.5 replacement_number 15 Example 12 This program illustrates the use of order-based strings. The string in this problem contains 26 letters, a to z. It tries to put them in alphabetic order. the ga generated the following string (objective score is 26): abcdefghijklmnopqrstuvwxyz GAStringGenome Example 13 This program runs a GA-within-GA. The outer level GA tries to match the pattern read in from a file. The inner level GA is run only when the outer GA reaches a threshhold objective score then it tries to match a sequence of numbers that were generated randomly at the beginning of the program's execution. You might have to run the primary GA for more than 5000 generations to get a score high enough to kick in the secondary genetic algorithm. Use the ngen option to do this on the command line. input pattern: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * input sequence: 0.265886 54.6261 3 -2.85019 69151.2 0.00150462 2 the ga generated: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 0.411765 12.9412 3 -2.16471 74143.5 0.00749412 6.17647 best of generation data are in 'bog.dat' Example 14 This example shows how to create a genome that contains a list of lists. We create a composite genome that has lists in it. Each list has some nodes, only one of which contains the number 0. The objective is to move the node with number 0 in it to the nth position where n is the number of the list within the composite genome. a randomly-generated set of paths: list 0: 28 20 21 22 25 24 0 26 23 27 list 1: 22 20 23 21 0 24 25 26 28 27 list 2: 20 23 21 28 27 24 22 26 0 25 list 3: 0 20 21 22 23 24 27 26 25 28 list 4: 0 28 21 22 23 24 27 26 20 25 list 5: 28 27 21 26 23 24 25 22 20 0 the ga generated: list 0: 0 26 24 22 25 23 27 28 21 20 list 1: 24 0 20 26 23 22 25 27 21 28 list 2: 21 26 0 22 23 20 25 27 28 24 list 3: 24 21 22 0 23 27 25 20 26 28 list 4: 24 26 23 21 0 20 22 28 27 25 list 5: 20 26 21 25 23 0 24 22 27 28 Example 15 This program generates a sequence of random numbers then uses a simple GA and binary-to-decimal genome to match the sequence. It uses the convergence of the best-of-generation as the criterion for when to stop. input sequence: 0.265886 54.6261 3 -2.85019 69151.2 0.00150462 2 random values in the genome: 0.419608 85.098 3 -4.90588 6760 0.00834118 5.92941 the ga generated: 0.247059 49.8039 3 -2.74118 60823.5 0.00156471 2.00392 Example 16 This example uses a SteadyState GA and Tree genome. It tries to maximize the size of the tree genomes that it contains. The genomes contain points in its nodes. Two different runs are made: first with the swap subtree mutator, second with the destructive mutator. initializing...evolving for 10 generations............. the ga generated a tree with 37 nodes, 9 levels deep. initializing...evolving for 10 generations............. the ga generated a tree with 35 nodes, 12 levels deep. Example 17 This program illustrates the use of a 2DArrayGenome with three alleles. It tries to fill a 2D array with alternating 0s and 1s, and -1s at the corners. You will have to run it for something like 10000 generations to get the perfect score. evolving........................................................................................................................................................................................................... the ga generated: -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 Example 18 This program is designed to compare the GA types. You can specify steady-state, incremental, or simple GA and tweak any of the parameters for each of these GA types. The objective function tries to match a pattern read in from a file. input pattern: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * the ga generated: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * the statistics for the run are: 400 # current generation 0.990521 # current convergence 12000 # number of selections since initialization 10776 # number of crossovers since initialization 2707 # number of mutations since initialization 12000 # number of replacements since initialization 11051 # number of genome evaluations since initialization 201 # number of population evaluations since initialization 211 # maximum score since initialization 88 # minimum score since initialization 182.65 # average of all scores ('on-line' performance) 187.255 # average of maximum scores ('off-line' performance) 178.163 # average of minimum scores ('off-line' performance) 112.9 # mean score in initial population 127 # maximum score in initial population 88 # minimum score in initial population 7.63996 # standard deviation of initial population -1 # diversity of initial population (0=identical,-1=unset) 207.2 # mean score in current population 211 # maximum score in current population 203 # minimum score in current population 2.49689 # standard deviation of current population -1 # diversity of current population (0=identical,-1=unset) 20 # how far back to look for convergence 10 # how often to record scores 50 # how often to write scores to file bog.dat # name of file to which scores are written the objective function was called 11051 times best of generation data are in 'bog.dat' Example 19 This program runs the DeJong test problems. running DeJong function number 1 ... the ga generated: 5.11 -5.12 -5.12 the statistics for the run are: 400 # current generation 1 # current convergence 3200 # number of selections since initialization 2481 # number of crossovers since initialization 152 # number of mutations since initialization 2800 # number of replacements since initialization 2524 # number of genome evaluations since initialization 401 # number of population evaluations since initialization 78.5409 # maximum score since initialization 0.342654 # minimum score since initialization 77.4228 # average of all scores ('on-line' performance) 78.0059 # average of maximum scores ('off-line' performance) 77.0203 # average of minimum scores ('off-line' performance) 25.943 # mean score in initial population 76.0281 # maximum score in initial population 0.342654 # minimum score in initial population 14.6341 # standard deviation of initial population -1 # diversity of initial population (0=identical,-1=unset) 78.5409 # mean score in current population 78.5409 # maximum score in current population 78.5409 # minimum score in current population 7.75982e-06 # standard deviation of current population -1 # diversity of current population (0=identical,-1=unset) 20 # how far back to look for convergence 10 # how often to record scores 50 # how often to write scores to file bog.dat # name of file to which scores are written best-of-generation data are in 'bog.dat' Example 20 Running Holland's Royal Road test problem with a genome that is 240 bits long (16 blocks). The parameters are as follows: block size: 8 gap size: 7 m*: 4 u*: 1 u: 0.3 v: 0.02 the ga generated: 111111110111000111111110100000111111111010110101001011111010111111110001010110001010011100111111110010101111111110110001100110011000010011101000101101110010101101000111111111101100111111111100101111111111001100101001100111101111111110001011 the highest level achieved was 1 the statistics for the run are: 10000 # current generation 1 # current convergence 2560000 # number of selections since initialization 2305756 # number of crossovers since initialization 613723 # number of mutations since initialization 2560000 # number of replacements since initialization 2360486 # number of genome evaluations since initialization 10001 # number of population evaluations since initialization 5.78 # maximum score since initialization -0.06 # minimum score since initialization 5.77284 # average of all scores ('on-line' performance) 5.77559 # average of maximum scores ('off-line' performance) 5.77193 # average of minimum scores ('off-line' performance) 0.541289 # mean score in initial population 1.9 # maximum score in initial population -0.06 # minimum score in initial population 0.303989 # standard deviation of initial population -1 # diversity of initial population (0=identical,-1=unset) 5.78002 # mean score in current population 5.78 # maximum score in current population 5.78 # minimum score in current population 2.43425e-05 # standard deviation of current population -1 # diversity of current population (0=identical,-1=unset) 20 # how far back to look for convergence 20 # how often to record scores 100 # how often to write scores to file bog.dat # name of file to which scores are written the parameters for the run are: minimaxi 1 number_of_generations 10000 generations_to_convergence 20 convergence_percentage 0.99 crossover_probability 0.9 mutation_probability 0.001 population_size 512 score_frequency 20 flush_frequency 100 record_diversity 0 score_filename bog.dat select_scores 2 number_of_best 1 replacement_percentage 0.5 replacement_number 256 Example 21 This example shows various uses of the allele set object in combination with the real number genome. running ga number 1 (alternate allele(0) and allele(3))... the ga generated: -10 10 -10 10 -10 10 -10 10 running ga number 2 (continuous descending order)... the ga generated: 0.722113 0.690404 0.475627 0.443254 0.413628 0.307699 0.286382 0.0776234 running ga number 2a (descending order, EXCLUSIVE)... the ga generated: 0.877096 0.635132 0.0272497 0.92776 0.512969 0.228361 0.17755 0.021867 running ga number 3 (discretized ascending order)... the ga generated: 2.5 3 4 4.5 6 7 9 9.5 running ga number 4 (maximize each gene)... the ga generated: 10 100 -5 -0.0001 11000 Example 22 This example shows how to derive your own genetic algorithm class. Here we use a custom, single-child crossover and a modified replacement strategy with overlapping populations. initializing... evolving.......... dumping the function to file... initial population is in 'pop.initial.dat' final population is in 'pop.final.dat' the function is in 'sinusoid.dat' parameters were: minimaxi 1 number_of_generations 500 generations_to_convergence 20 convergence_percentage 0.99 crossover_probability 1 mutation_probability 0.01 population_size 100 score_frequency 10 flush_frequency 100 record_diversity 0 score_filename bog.dat select_scores 255 number_of_best 1 replacement_percentage 0.25 replacement_number 25 Example 23 This program tries to maximize or minimize, depending on the command line argument that you give it. Use the command-line argument 'mm -1' to minimize (the default for this example), or 'mm 1' to maximize. The objective function is a simple sinusoidal. printing initial population to file... printing final population to file... printing function to file... Example 24 This example illustrates how to derive your own genetic algorithm. This genetic algorithm does restricted mating and uses a selector slightly more finicky than a uniform random selector. The objective function is a simple sinusoidal. printing population to file 'population.dat'... printing function to file 'sinusoid.dat'... Example 25 This example uses a genetic algorithm with multiple populations. initializing...evolving....................................................................................................... best individual is: 11111111111111111111111111111111 100 # current generation 1 # current convergence 13000 # number of selections since initialization 12500 # number of crossovers since initialization 12024 # number of mutations since initialization 12500 # number of replacements since initialization 12650 # number of genome evaluations since initialization 1005 # number of population evaluations since initialization 1 # maximum score since initialization 0 # minimum score since initialization 0.163021 # average of all scores ('on-line' performance) 0.984688 # average of maximum scores ('off-line' performance) 0 # average of minimum scores ('off-line' performance) 0.1125 # mean score in initial population 0.6875 # maximum score in initial population 0 # minimum score in initial population 0.255937 # standard deviation of initial population -1 # diversity of initial population (0=identical,-1=unset) 0.166667 # mean score in current population 1 # maximum score in current population 0 # minimum score in current population 0.379049 # standard deviation of current population -1 # diversity of current population (0=identical,-1=unset) 20 # how far back to look for convergence 1 # how often to record scores 0 # how often to write scores to file generations.dat # name of file to which scores are written Example 26 The Travelling Salesman Problem (TSP) demo program. initializing...evolving...10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 170 180 190 200 210 220 230 240 250 260 270 280 290 300 310 320 330 340 350 360 370 380 390 400 410 420 430 440 450 460 470 480 490 500 510 520 530 540 550 560 570 580 590 600 610 620 630 640 650 660 670 680 690 700 710 720 730 740 750 760 770 780 790 800 810 820 830 840 850 860 870 880 890 900 910 920 930 940 950 960 970 980 990 1000 the shortest path found is 22.6503 this is the distance from the sequence 5 6 10 14 18 19 15 11 7 3 2 1 20 0 4 8 12 16 17 13 9 1000 # current generation 1 # current convergence 100000 # number of selections since initialization 100000 # number of crossovers since initialization 10014 # number of mutations since initialization 100000 # number of replacements since initialization 100100 # number of genome evaluations since initialization 1001 # number of population evaluations since initialization 64.3227 # maximum score since initialization 22.6503 # minimum score since initialization 23.1627 # average of all scores ('on-line' performance) 23.2063 # average of maximum scores ('off-line' performance) 23.0545 # average of minimum scores ('off-line' performance) 54.0745 # mean score in initial population 64.3227 # maximum score in initial population 44.4397 # minimum score in initial population 4.07012 # standard deviation of initial population -1 # diversity of initial population (0=identical,-1=unset) 22.6503 # mean score in current population 22.6503 # maximum score in current population 22.6503 # minimum score in current population 2.66312e-06 # standard deviation of current population -1 # diversity of current population (0=identical,-1=unset) 20 # how far back to look for convergence 100 # how often to record scores 0 # how often to write scores to file generations.dat # name of file to which scores are written Example 27 Deterministic crowding demonstration program. In addition to the standard GAlib command-line arguments, you can specify one of the four following functions: 0 - modified Himmelblau's function 1 - Foxholes (25) 2 - Schwefel's nasty (1 glob. Max bei (420.96/420.96) 3 - Mexican Hat (optimum at 0,0) best individual is 3.00116 1.99599 100 # current generation 0.999999 # current convergence 10000 # number of selections since initialization 5000 # number of crossovers since initialization 245 # number of mutations since initialization 953 # number of replacements since initialization 5100 # number of genome evaluations since initialization 101 # number of population evaluations since initialization 10 # maximum score since initialization 5.06767 # minimum score since initialization 9.90808 # average of all scores ('on-line' performance) 9.99984 # average of maximum scores ('off-line' performance) 9.35658 # average of minimum scores ('off-line' performance) 8.84823 # mean score in initial population 9.99917 # maximum score in initial population 5.06767 # minimum score in initial population 1.05433 # standard deviation of initial population -1 # diversity of initial population (0=identical,-1=unset) 9.99484 # mean score in current population 10 # maximum score in current population 9.96593 # minimum score in current population 0.00755568 # standard deviation of current population -1 # diversity of current population (0=identical,-1=unset) 20 # how far back to look for convergence 100 # how often to record scores 0 # how often to write scores to file generations.dat # name of file to which scores are written galib247/examples/results/test_results-linux.txt0100644003643600364360000006575110573535476021440 0ustar mwallmwall./randtest: Random Number Test Using the RAN2 random number generator (RNG). Using specified random seed 555 Library thinks the random seed is 555 running the chi-square test for randomness of the RNG... (there will be some failures of the chi-square test) integer test (1000): chi-squared should be within 20 of 100 run #0 93.2 run #1 101.52 run #2 119.752 run #3 103.175 run #4 130.718 ***failed*** run #5 118.672 run #6 93.8672 run #7 101.787 run #8 132.579 ***failed*** run #9 114.258 integer test (10000): chi-squared should be within 20 of 100 run #0 88.2 run #1 87.82 run #2 77.3 ***failed*** run #3 81.22 run #4 94.18 run #5 113.46 run #6 102.72 run #7 94.24 run #8 71.24 ***failed*** run #9 117.86 integer test (10000): chi-squared should be within 20 of 100 run #0 109.12 run #1 113.06 run #2 133.26 ***failed*** run #3 99.82 run #4 109.18 run #5 90.52 run #6 100.58 run #7 101.34 run #8 93.74 run #9 89.38 integer test (100000): chi-squared should be within 20 of 100 run #0 119.2 run #1 99.978 run #2 110.9 run #3 103.678 run #4 82.366 run #5 102.464 run #6 91.632 run #7 86.788 run #8 109.812 run #9 86.968 Example 1 This program tries to fill a 2DBinaryStringGenome with alternating 1s and 0s using a SimpleGA The GA found: 0101010101 1010101010 0101010101 1010101010 0101010101 Example 2 This program generates a sequence of random numbers then uses a simple GA and binary-to-decimal genome to match the sequence. input sequence: 0.265886 54.6261 3 -2.85019 69151.2 0.00150462 2 random values in the genome: 0.980392 18.4314 3 -4.34118 23997.6 0.00276471 0.494118 the ga generated: 0.278431 54.5098 3 -2.87059 2450.59 0.00163529 2.00392 best of generation data are in 'bog.dat' Example 3 This program reads in a data file then runs a simple GA whose objective function tries to match the pattern of bits that are in the data file. input pattern: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * best of generation data are in 'bog.dat' the ga generated: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Example 4 This program tries to fill a 3DBinaryStringGenome with alternating 1s and 0s using a SteadyStateGA the ga generated: 0101010101 1010101010 0101010101 1010101010 0101010101 1010101010 0101010101 1010101010 0101010101 1010101010 0101010101 1010101010 0101010101 1010101010 0101010101 best of generation data are in 'bog.dat' Example 5 This program shows how to use a composite genome. It reads a matrix from a data file and a set of values to be matched in a binary-to-decimal genome then uses a steady-state GA to match the pattern and value set. input pattern: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * input sequence: 10.2 32.5 66 99.234 0.003 210 the ga generated: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 8.3767 32.4286 55.2418 101.924 0.00209011 150.615 Example 6 This example uses a SteadyState GA and Tree genome. It tries to maximize the size of the tree genomes that it contains. The genomes contain ints in its nodes. 8653 nodes, 120 levels deep. best of generation data are in 'bog.dat' Example 7 This program reads in a data file then runs a steady-state GA whose objective function tries to match the pattern of bits that are in the data file. input pattern: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * the ga generated: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * best of generation data are in 'bog.dat' Example 8 This program runs a steady-state GA whose objective function tries to maximize the size of the list and tries to make lists that contain the number 101 in the nodes. The lists contain ints in the nodes. the list contains 0 nodes the ga used the parameters: minimaxi 1 number_of_generations 50 generations_to_convergence 20 convergence_percentage 0.99 crossover_probability 0.6 mutation_probability 0.05 population_size 40 score_frequency 1 flush_frequency 10 record_diversity 0 score_filename bog.dat select_scores 7 number_of_best 1 replacement_percentage 0.5 replacement_number 20 Example 9 This program finds the maximum value in the function y = - x1^2 - x2^2 with the constraints -5 <= x1 <= 5 -5 <= x2 <= 5 the ga found an optimum at the point (7.62951e-05, 0.00328069) best of generation data are in 'bog.dat' Example 10 This program uses sharing to do speciation. The objective function has more than one optimum, so different genomes may have equally high scores. Speciation keeps the population from clustering at one optimum. Both gene-wise and phenotype-wise distance functions are used. Populations from all three runs are written to the files pop.nospec.dat, pop.genespec.dat and pop.phenespec.dat. The function is written to the file sinusoid.dat running with no speciation (fitness proportionate scaling)... the ga found an optimum at the point 3.2549 running the ga with speciation (sharing using bit-wise)... the ga found an optimum at the point 2.2549 running the ga with speciation (sharing using phenotype-wise)... the ga found an optimum at the point 4.2549 dumping the function to file... Example 11 This program illustrates the use of order-based lists. The list in this problem contains 25 numbers, 0 to 24. It tries to put them in descending order from 24 to 0. the ga generated the following list (objective score is 24): 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 best of generation data are in 'bog.dat' minimaxi 1 number_of_generations 1000 generations_to_convergence 20 convergence_percentage 0.99 crossover_probability 0.6 mutation_probability 0.01 population_size 30 score_frequency 10 flush_frequency 10 record_diversity 0 score_filename bog.dat select_scores 2 number_of_best 1 replacement_percentage 0.5 replacement_number 15 Example 12 This program illustrates the use of order-based strings. The string in this problem contains 26 letters, a to z. It tries to put them in alphabetic order. the ga generated the following string (objective score is 26): abcdefghijklmnopqrstuvwxyz GAStringGenome Example 13 This program runs a GA-within-GA. The outer level GA tries to match the pattern read in from a file. The inner level GA is run only when the outer GA reaches a threshhold objective score then it tries to match a sequence of numbers that were generated randomly at the beginning of the program's execution. You might have to run the primary GA for more than 5000 generations to get a score high enough to kick in the secondary genetic algorithm. Use the ngen option to do this on the command line. input pattern: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * input sequence: 0.265886 54.6261 3 -2.85019 69151.2 0.00150462 2 the ga generated: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 0.411765 12.9412 3 -2.16471 74143.5 0.00749412 6.17647 best of generation data are in 'bog.dat' Example 14 This example shows how to create a genome that contains a list of lists. We create a composite genome that has lists in it. Each list has some nodes, only one of which contains the number 0. The objective is to move the node with number 0 in it to the nth position where n is the number of the list within the composite genome. a randomly-generated set of paths: list 0: 28 20 21 22 25 24 0 26 23 27 list 1: 22 20 23 21 0 24 25 26 28 27 list 2: 20 23 21 28 27 24 22 26 0 25 list 3: 0 20 21 22 23 24 27 26 25 28 list 4: 0 28 21 22 23 24 27 26 20 25 list 5: 28 27 21 26 23 24 25 22 20 0 the ga generated: list 0: 0 26 24 22 25 23 27 28 21 20 list 1: 24 0 20 26 23 22 25 27 21 28 list 2: 21 26 0 22 23 20 25 27 28 24 list 3: 24 21 22 0 23 27 25 20 26 28 list 4: 24 26 23 21 0 20 22 28 27 25 list 5: 20 26 21 25 23 0 24 22 27 28 Example 15 This program generates a sequence of random numbers then uses a simple GA and binary-to-decimal genome to match the sequence. It uses the convergence of the best-of-generation as the criterion for when to stop. input sequence: 0.265886 54.6261 3 -2.85019 69151.2 0.00150462 2 random values in the genome: 0.419608 85.098 3 -4.90588 6760 0.00834118 5.92941 the ga generated: 0.247059 49.8039 3 -2.74118 60823.5 0.00156471 2.00392 Example 16 This example uses a SteadyState GA and Tree genome. It tries to maximize the size of the tree genomes that it contains. The genomes contain points in its nodes. Two different runs are made: first with the swap subtree mutator, second with the destructive mutator. initializing...evolving for 10 generations............. the ga generated a tree with 37 nodes, 9 levels deep. initializing...evolving for 10 generations............. the ga generated a tree with 35 nodes, 12 levels deep. Example 17 This program illustrates the use of a 2DArrayGenome with three alleles. It tries to fill a 2D array with alternating 0s and 1s, and -1s at the corners. You will have to run it for something like 10000 generations to get the perfect score. evolving........................................................................................................................................................................................................... the ga generated: -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 Example 18 This program is designed to compare the GA types. You can specify steady-state, incremental, or simple GA and tweak any of the parameters for each of these GA types. The objective function tries to match a pattern read in from a file. input pattern: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * the ga generated: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * the statistics for the run are: 400 # current generation 0.990521 # current convergence 12000 # number of selections since initialization 10776 # number of crossovers since initialization 2707 # number of mutations since initialization 12000 # number of replacements since initialization 11051 # number of genome evaluations since initialization 201 # number of population evaluations since initialization 211 # maximum score since initialization 88 # minimum score since initialization 182.65 # average of all scores ('on-line' performance) 187.255 # average of maximum scores ('off-line' performance) 178.162 # average of minimum scores ('off-line' performance) 112.9 # mean score in initial population 127 # maximum score in initial population 88 # minimum score in initial population 7.63996 # standard deviation of initial population -1 # diversity of initial population (0=identical,-1=unset) 207.2 # mean score in current population 211 # maximum score in current population 203 # minimum score in current population 2.49689 # standard deviation of current population -1 # diversity of current population (0=identical,-1=unset) 20 # how far back to look for convergence 10 # how often to record scores 50 # how often to write scores to file bog.dat # name of file to which scores are written the objective function was called 11051 times best of generation data are in 'bog.dat' Example 19 This program runs the DeJong test problems. running DeJong function number 1 ... the ga generated: 5.11 -5.12 -5.12 the statistics for the run are: 400 # current generation 1 # current convergence 3200 # number of selections since initialization 2481 # number of crossovers since initialization 152 # number of mutations since initialization 2800 # number of replacements since initialization 2524 # number of genome evaluations since initialization 401 # number of population evaluations since initialization 78.5409 # maximum score since initialization 0.342654 # minimum score since initialization 77.4228 # average of all scores ('on-line' performance) 78.006 # average of maximum scores ('off-line' performance) 77.0203 # average of minimum scores ('off-line' performance) 25.943 # mean score in initial population 76.0281 # maximum score in initial population 0.342654 # minimum score in initial population 14.6341 # standard deviation of initial population -1 # diversity of initial population (0=identical,-1=unset) 78.5409 # mean score in current population 78.5409 # maximum score in current population 78.5409 # minimum score in current population 7.75982e-06 # standard deviation of current population -1 # diversity of current population (0=identical,-1=unset) 20 # how far back to look for convergence 10 # how often to record scores 50 # how often to write scores to file bog.dat # name of file to which scores are written best-of-generation data are in 'bog.dat' Example 20 Running Holland's Royal Road test problem with a genome that is 240 bits long (16 blocks). The parameters are as follows: block size: 8 gap size: 7 m*: 4 u*: 1 u: 0.3 v: 0.02 the ga generated: 110010100110101111111110100011010111000001101111111110010111011000111001011110001010011100111111111000101111111110110001100110011010111011110000011011011000110101000111111110111000101000111111001111111110011001001110010111101111111110101000 the highest level achieved was 1 the statistics for the run are: 10000 # current generation 1 # current convergence 2560000 # number of selections since initialization 2305756 # number of crossovers since initialization 613723 # number of mutations since initialization 2560000 # number of replacements since initialization 2360486 # number of genome evaluations since initialization 10001 # number of population evaluations since initialization 4.52 # maximum score since initialization -0.06 # minimum score since initialization 4.51608 # average of all scores ('on-line' performance) 4.51795 # average of maximum scores ('off-line' performance) 4.51532 # average of minimum scores ('off-line' performance) 0.541289 # mean score in initial population 1.9 # maximum score in initial population -0.06 # minimum score in initial population 0.303989 # standard deviation of initial population -1 # diversity of initial population (0=identical,-1=unset) 4.52001 # mean score in current population 4.52 # maximum score in current population 4.52 # minimum score in current population 1.38418e-05 # standard deviation of current population -1 # diversity of current population (0=identical,-1=unset) 20 # how far back to look for convergence 20 # how often to record scores 100 # how often to write scores to file bog.dat # name of file to which scores are written the parameters for the run are: minimaxi 1 number_of_generations 10000 generations_to_convergence 20 convergence_percentage 0.99 crossover_probability 0.9 mutation_probability 0.001 population_size 512 score_frequency 20 flush_frequency 100 record_diversity 0 score_filename bog.dat select_scores 2 number_of_best 1 replacement_percentage 0.5 replacement_number 256 Example 21 This example shows various uses of the allele set object in combination with the real number genome. running ga number 1 (alternate allele(0) and allele(3))... the ga generated: -10 10 -10 10 -10 10 -10 10 running ga number 2 (continuous descending order)... the ga generated: 0.722113 0.690404 0.475627 0.443254 0.413628 0.307699 0.286382 0.0776234 running ga number 2a (descending order, EXCLUSIVE)... the ga generated: 0.877096 0.635132 0.0272497 0.92776 0.512969 0.228361 0.17755 0.021867 running ga number 3 (discretized ascending order)... the ga generated: 2.5 3 4 4.5 6 7 9 9.5 running ga number 4 (maximize each gene)... the ga generated: 10 100 -5 -1e-04 11000 Example 22 This example shows how to derive your own genetic algorithm class. Here we use a custom, single-child crossover and a modified replacement strategy with overlapping populations. initializing... evolving.......... dumping the function to file... initial population is in 'pop.initial.dat' final population is in 'pop.final.dat' the function is in 'sinusoid.dat' parameters were: minimaxi 1 number_of_generations 500 generations_to_convergence 20 convergence_percentage 0.99 crossover_probability 1 mutation_probability 0.01 population_size 100 score_frequency 10 flush_frequency 100 record_diversity 0 score_filename bog.dat select_scores 255 number_of_best 1 replacement_percentage 0.25 replacement_number 25 Example 23 This program tries to maximize or minimize, depending on the command line argument that you give it. Use the command-line argument 'mm -1' to minimize (the default for this example), or 'mm 1' to maximize. The objective function is a simple sinusoidal. printing initial population to file... printing final population to file... printing function to file... Example 24 This example illustrates how to derive your own genetic algorithm. This genetic algorithm does restricted mating and uses a selector slightly more finicky than a uniform random selector. The objective function is a simple sinusoidal. printing population to file 'population.dat'... printing function to file 'sinusoid.dat'... Example 25 This example uses a genetic algorithm with multiple populations. initializing...evolving....................................................................................................... best individual is: 11111111111111111111111111111111 100 # current generation 1 # current convergence 13000 # number of selections since initialization 12500 # number of crossovers since initialization 12024 # number of mutations since initialization 12500 # number of replacements since initialization 12650 # number of genome evaluations since initialization 1005 # number of population evaluations since initialization 1 # maximum score since initialization 0 # minimum score since initialization 0.163021 # average of all scores ('on-line' performance) 0.984688 # average of maximum scores ('off-line' performance) 0 # average of minimum scores ('off-line' performance) 0.1125 # mean score in initial population 0.6875 # maximum score in initial population 0 # minimum score in initial population 0.255937 # standard deviation of initial population -1 # diversity of initial population (0=identical,-1=unset) 0.166667 # mean score in current population 1 # maximum score in current population 0 # minimum score in current population 0.379049 # standard deviation of current population -1 # diversity of current population (0=identical,-1=unset) 20 # how far back to look for convergence 1 # how often to record scores 0 # how often to write scores to file generations.dat # name of file to which scores are written Example 26 The Travelling Salesman Problem (TSP) demo program. initializing...evolving...10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 170 180 190 200 210 220 230 240 250 260 270 280 290 300 310 320 330 340 350 360 370 380 390 400 410 420 430 440 450 460 470 480 490 500 510 520 530 540 550 560 570 580 590 600 610 620 630 640 650 660 670 680 690 700 710 720 730 740 750 760 770 780 790 800 810 820 830 840 850 860 870 880 890 900 910 920 930 940 950 960 970 980 990 1000 the shortest path found is 22.6503 this is the distance from the sequence 5 6 10 14 18 19 15 11 7 3 2 1 20 0 4 8 12 16 17 13 9 1000 # current generation 1 # current convergence 100000 # number of selections since initialization 100000 # number of crossovers since initialization 10014 # number of mutations since initialization 100000 # number of replacements since initialization 100100 # number of genome evaluations since initialization 1001 # number of population evaluations since initialization 64.3227 # maximum score since initialization 22.6503 # minimum score since initialization 23.1626 # average of all scores ('on-line' performance) 23.2062 # average of maximum scores ('off-line' performance) 23.0545 # average of minimum scores ('off-line' performance) 54.0745 # mean score in initial population 64.3227 # maximum score in initial population 44.4397 # minimum score in initial population 4.07012 # standard deviation of initial population -1 # diversity of initial population (0=identical,-1=unset) 22.6503 # mean score in current population 22.6503 # maximum score in current population 22.6503 # minimum score in current population 2.66312e-06 # standard deviation of current population -1 # diversity of current population (0=identical,-1=unset) 20 # how far back to look for convergence 100 # how often to record scores 0 # how often to write scores to file generations.dat # name of file to which scores are written Example 27 Deterministic crowding demonstration program. In addition to the standard GAlib command-line arguments, you can specify one of the four following functions: 0 - modified Himmelblau's function 1 - Foxholes (25) 2 - Schwefel's nasty (1 glob. Max bei (420.96/420.96) 3 - Mexican Hat (optimum at 0,0) best individual is 3.00116 1.99599 100 # current generation 0.999999 # current convergence 10000 # number of selections since initialization 5000 # number of crossovers since initialization 245 # number of mutations since initialization 953 # number of replacements since initialization 5100 # number of genome evaluations since initialization 101 # number of population evaluations since initialization 10 # maximum score since initialization 5.06768 # minimum score since initialization 9.90808 # average of all scores ('on-line' performance) 9.99984 # average of maximum scores ('off-line' performance) 9.35657 # average of minimum scores ('off-line' performance) 8.84823 # mean score in initial population 9.99917 # maximum score in initial population 5.06768 # minimum score in initial population 1.05433 # standard deviation of initial population -1 # diversity of initial population (0=identical,-1=unset) 9.99484 # mean score in current population 10 # maximum score in current population 9.96593 # minimum score in current population 0.00755568 # standard deviation of current population -1 # diversity of current population (0=identical,-1=unset) 20 # how far back to look for convergence 100 # how often to record scores 0 # how often to write scores to file generations.dat # name of file to which scores are written galib247/examples/results/test_results-macosx.txt0100644003643600364360000006575310573535476021575 0ustar mwallmwall./randtest: Random Number Test Using the RAN2 random number generator (RNG). Using specified random seed 555 Library thinks the random seed is 555 running the chi-square test for randomness of the RNG... (there will be some failures of the chi-square test) integer test (1000): chi-squared should be within 20 of 100 run #0 93.2 run #1 101.52 run #2 119.752 run #3 103.175 run #4 130.718 ***failed*** run #5 118.672 run #6 93.8672 run #7 101.787 run #8 132.579 ***failed*** run #9 114.258 integer test (10000): chi-squared should be within 20 of 100 run #0 88.2 run #1 87.82 run #2 77.3 ***failed*** run #3 81.22 run #4 94.18 run #5 113.46 run #6 102.72 run #7 94.24 run #8 71.24 ***failed*** run #9 117.86 integer test (10000): chi-squared should be within 20 of 100 run #0 109.12 run #1 113.06 run #2 133.26 ***failed*** run #3 99.82 run #4 109.18 run #5 90.52 run #6 100.58 run #7 101.34 run #8 93.74 run #9 89.38 integer test (100000): chi-squared should be within 20 of 100 run #0 119.2 run #1 99.978 run #2 110.9 run #3 103.678 run #4 82.366 run #5 102.464 run #6 91.632 run #7 86.788 run #8 109.812 run #9 86.968 Example 1 This program tries to fill a 2DBinaryStringGenome with alternating 1s and 0s using a SimpleGA The GA found: 0101010101 1010101010 0101010101 1010101010 0101010101 Example 2 This program generates a sequence of random numbers then uses a simple GA and binary-to-decimal genome to match the sequence. input sequence: 0.265886 54.6261 3 -2.85019 69151.2 0.00150462 2 random values in the genome: 0.980392 18.4314 3 -4.34118 23997.6 0.00276471 0.494118 the ga generated: 0.278431 54.5098 3 -2.87059 2450.59 0.00163529 2.00392 best of generation data are in 'bog.dat' Example 3 This program reads in a data file then runs a simple GA whose objective function tries to match the pattern of bits that are in the data file. input pattern: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * best of generation data are in 'bog.dat' the ga generated: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Example 4 This program tries to fill a 3DBinaryStringGenome with alternating 1s and 0s using a SteadyStateGA the ga generated: 0101010101 1010101010 0101010101 1010101010 0101010101 1010101010 0101010101 1010101010 0101010101 1010101010 0101010101 1010101010 0101010101 1010101010 0101010101 best of generation data are in 'bog.dat' Example 5 This program shows how to use a composite genome. It reads a matrix from a data file and a set of values to be matched in a binary-to-decimal genome then uses a steady-state GA to match the pattern and value set. input pattern: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * input sequence: 10.2 32.5 66 99.234 0.003 210 the ga generated: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 8.3767 32.4286 55.2418 101.924 0.00209011 150.615 Example 6 This example uses a SteadyState GA and Tree genome. It tries to maximize the size of the tree genomes that it contains. The genomes contain ints in its nodes. 8653 nodes, 120 levels deep. best of generation data are in 'bog.dat' Example 7 This program reads in a data file then runs a steady-state GA whose objective function tries to match the pattern of bits that are in the data file. input pattern: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * the ga generated: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * best of generation data are in 'bog.dat' Example 8 This program runs a steady-state GA whose objective function tries to maximize the size of the list and tries to make lists that contain the number 101 in the nodes. The lists contain ints in the nodes. the list contains 0 nodes the ga used the parameters: minimaxi 1 number_of_generations 50 generations_to_convergence 20 convergence_percentage 0.99 crossover_probability 0.6 mutation_probability 0.05 population_size 40 score_frequency 1 flush_frequency 10 record_diversity 0 score_filename bog.dat select_scores 7 number_of_best 1 replacement_percentage 0.5 replacement_number 20 Example 9 This program finds the maximum value in the function y = - x1^2 - x2^2 with the constraints -5 <= x1 <= 5 -5 <= x2 <= 5 the ga found an optimum at the point (7.62939e-05, 0.00328064) best of generation data are in 'bog.dat' Example 10 This program uses sharing to do speciation. The objective function has more than one optimum, so different genomes may have equally high scores. Speciation keeps the population from clustering at one optimum. Both gene-wise and phenotype-wise distance functions are used. Populations from all three runs are written to the files pop.nospec.dat, pop.genespec.dat and pop.phenespec.dat. The function is written to the file sinusoid.dat running with no speciation (fitness proportionate scaling)... the ga found an optimum at the point 3.2549 running the ga with speciation (sharing using bit-wise)... the ga found an optimum at the point 2.2549 running the ga with speciation (sharing using phenotype-wise)... the ga found an optimum at the point 4.2549 dumping the function to file... Example 11 This program illustrates the use of order-based lists. The list in this problem contains 25 numbers, 0 to 24. It tries to put them in descending order from 24 to 0. the ga generated the following list (objective score is 24): 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 best of generation data are in 'bog.dat' minimaxi 1 number_of_generations 1000 generations_to_convergence 20 convergence_percentage 0.99 crossover_probability 0.6 mutation_probability 0.01 population_size 30 score_frequency 10 flush_frequency 10 record_diversity 0 score_filename bog.dat select_scores 2 number_of_best 1 replacement_percentage 0.5 replacement_number 15 Example 12 This program illustrates the use of order-based strings. The string in this problem contains 26 letters, a to z. It tries to put them in alphabetic order. the ga generated the following string (objective score is 26): abcdefghijklmnopqrstuvwxyz GAStringGenome Example 13 This program runs a GA-within-GA. The outer level GA tries to match the pattern read in from a file. The inner level GA is run only when the outer GA reaches a threshhold objective score then it tries to match a sequence of numbers that were generated randomly at the beginning of the program's execution. You might have to run the primary GA for more than 5000 generations to get a score high enough to kick in the secondary genetic algorithm. Use the ngen option to do this on the command line. input pattern: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * input sequence: 0.265886 54.6261 3 -2.85019 69151.2 0.00150462 2 the ga generated: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 0.411765 12.9412 3 -2.16471 74143.5 0.00749412 6.17647 best of generation data are in 'bog.dat' Example 14 This example shows how to create a genome that contains a list of lists. We create a composite genome that has lists in it. Each list has some nodes, only one of which contains the number 0. The objective is to move the node with number 0 in it to the nth position where n is the number of the list within the composite genome. a randomly-generated set of paths: list 0: 28 20 21 22 25 24 0 26 23 27 list 1: 22 20 23 21 0 24 25 26 28 27 list 2: 20 23 21 28 27 24 22 26 0 25 list 3: 0 20 21 22 23 24 27 26 25 28 list 4: 0 28 21 22 23 24 27 26 20 25 list 5: 28 27 21 26 23 24 25 22 20 0 the ga generated: list 0: 0 26 24 22 25 23 27 28 21 20 list 1: 24 0 20 26 23 22 25 27 21 28 list 2: 21 26 0 22 23 20 25 27 28 24 list 3: 24 21 22 0 23 27 25 20 26 28 list 4: 24 26 23 21 0 20 22 28 27 25 list 5: 20 26 21 25 23 0 24 22 27 28 Example 15 This program generates a sequence of random numbers then uses a simple GA and binary-to-decimal genome to match the sequence. It uses the convergence of the best-of-generation as the criterion for when to stop. input sequence: 0.265886 54.6261 3 -2.85019 69151.2 0.00150462 2 random values in the genome: 0.419608 85.098 3 -4.90588 6760 0.00834118 5.92941 the ga generated: 0.247059 49.8039 3 -2.74118 60823.5 0.00156471 2.00392 Example 16 This example uses a SteadyState GA and Tree genome. It tries to maximize the size of the tree genomes that it contains. The genomes contain points in its nodes. Two different runs are made: first with the swap subtree mutator, second with the destructive mutator. initializing...evolving for 10 generations............. the ga generated a tree with 37 nodes, 9 levels deep. initializing...evolving for 10 generations............. the ga generated a tree with 35 nodes, 12 levels deep. Example 17 This program illustrates the use of a 2DArrayGenome with three alleles. It tries to fill a 2D array with alternating 0s and 1s, and -1s at the corners. You will have to run it for something like 10000 generations to get the perfect score. evolving........................................................................................................................................................................................................... the ga generated: -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 Example 18 This program is designed to compare the GA types. You can specify steady-state, incremental, or simple GA and tweak any of the parameters for each of these GA types. The objective function tries to match a pattern read in from a file. input pattern: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * the ga generated: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * the statistics for the run are: 400 # current generation 0.990521 # current convergence 12000 # number of selections since initialization 10776 # number of crossovers since initialization 2707 # number of mutations since initialization 12000 # number of replacements since initialization 11051 # number of genome evaluations since initialization 201 # number of population evaluations since initialization 211 # maximum score since initialization 88 # minimum score since initialization 182.65 # average of all scores ('on-line' performance) 187.255 # average of maximum scores ('off-line' performance) 178.163 # average of minimum scores ('off-line' performance) 112.9 # mean score in initial population 127 # maximum score in initial population 88 # minimum score in initial population 7.63996 # standard deviation of initial population -1 # diversity of initial population (0=identical,-1=unset) 207.2 # mean score in current population 211 # maximum score in current population 203 # minimum score in current population 2.49689 # standard deviation of current population -1 # diversity of current population (0=identical,-1=unset) 20 # how far back to look for convergence 10 # how often to record scores 50 # how often to write scores to file bog.dat # name of file to which scores are written the objective function was called 11051 times best of generation data are in 'bog.dat' Example 19 This program runs the DeJong test problems. running DeJong function number 1 ... the ga generated: 5.11 -5.12 -5.12 the statistics for the run are: 400 # current generation 1 # current convergence 3200 # number of selections since initialization 2481 # number of crossovers since initialization 152 # number of mutations since initialization 2800 # number of replacements since initialization 2524 # number of genome evaluations since initialization 401 # number of population evaluations since initialization 78.5409 # maximum score since initialization 0.342654 # minimum score since initialization 77.4228 # average of all scores ('on-line' performance) 78.0059 # average of maximum scores ('off-line' performance) 77.0203 # average of minimum scores ('off-line' performance) 25.943 # mean score in initial population 76.0281 # maximum score in initial population 0.342654 # minimum score in initial population 14.6341 # standard deviation of initial population -1 # diversity of initial population (0=identical,-1=unset) 78.5409 # mean score in current population 78.5409 # maximum score in current population 78.5409 # minimum score in current population 7.75982e-06 # standard deviation of current population -1 # diversity of current population (0=identical,-1=unset) 20 # how far back to look for convergence 10 # how often to record scores 50 # how often to write scores to file bog.dat # name of file to which scores are written best-of-generation data are in 'bog.dat' Example 20 Running Holland's Royal Road test problem with a genome that is 240 bits long (16 blocks). The parameters are as follows: block size: 8 gap size: 7 m*: 4 u*: 1 u: 0.3 v: 0.02 the ga generated: 111111110111000111111110100000111111111010110101001011111010111111110001010110001010011100111111110010101111111110110001100110011000010011101000101101110010101101000111111111101100111111111100101111111111001100101001100111101111111110001011 the highest level achieved was 1 the statistics for the run are: 10000 # current generation 1 # current convergence 2560000 # number of selections since initialization 2305756 # number of crossovers since initialization 613723 # number of mutations since initialization 2560000 # number of replacements since initialization 2360486 # number of genome evaluations since initialization 10001 # number of population evaluations since initialization 5.78 # maximum score since initialization -0.06 # minimum score since initialization 5.77284 # average of all scores ('on-line' performance) 5.77559 # average of maximum scores ('off-line' performance) 5.77193 # average of minimum scores ('off-line' performance) 0.541289 # mean score in initial population 1.9 # maximum score in initial population -0.06 # minimum score in initial population 0.303989 # standard deviation of initial population -1 # diversity of initial population (0=identical,-1=unset) 5.78002 # mean score in current population 5.78 # maximum score in current population 5.78 # minimum score in current population 2.43425e-05 # standard deviation of current population -1 # diversity of current population (0=identical,-1=unset) 20 # how far back to look for convergence 20 # how often to record scores 100 # how often to write scores to file bog.dat # name of file to which scores are written the parameters for the run are: minimaxi 1 number_of_generations 10000 generations_to_convergence 20 convergence_percentage 0.99 crossover_probability 0.9 mutation_probability 0.001 population_size 512 score_frequency 20 flush_frequency 100 record_diversity 0 score_filename bog.dat select_scores 2 number_of_best 1 replacement_percentage 0.5 replacement_number 256 Example 21 This example shows various uses of the allele set object in combination with the real number genome. running ga number 1 (alternate allele(0) and allele(3))... the ga generated: -10 10 -10 10 -10 10 -10 10 running ga number 2 (continuous descending order)... the ga generated: 0.722113 0.690404 0.475627 0.443254 0.413628 0.307699 0.286382 0.0776234 running ga number 2a (descending order, EXCLUSIVE)... the ga generated: 0.877096 0.635132 0.0272497 0.92776 0.512969 0.228361 0.17755 0.021867 running ga number 3 (discretized ascending order)... the ga generated: 2.5 3 4 4.5 6 7 9 9.5 running ga number 4 (maximize each gene)... the ga generated: 10 100 -5 -0.0001 11000 Example 22 This example shows how to derive your own genetic algorithm class. Here we use a custom, single-child crossover and a modified replacement strategy with overlapping populations. initializing... evolving.......... dumping the function to file... initial population is in 'pop.initial.dat' final population is in 'pop.final.dat' the function is in 'sinusoid.dat' parameters were: minimaxi 1 number_of_generations 500 generations_to_convergence 20 convergence_percentage 0.99 crossover_probability 1 mutation_probability 0.01 population_size 100 score_frequency 10 flush_frequency 100 record_diversity 0 score_filename bog.dat select_scores 255 number_of_best 1 replacement_percentage 0.25 replacement_number 25 Example 23 This program tries to maximize or minimize, depending on the command line argument that you give it. Use the command-line argument 'mm -1' to minimize (the default for this example), or 'mm 1' to maximize. The objective function is a simple sinusoidal. printing initial population to file... printing final population to file... printing function to file... Example 24 This example illustrates how to derive your own genetic algorithm. This genetic algorithm does restricted mating and uses a selector slightly more finicky than a uniform random selector. The objective function is a simple sinusoidal. printing population to file 'population.dat'... printing function to file 'sinusoid.dat'... Example 25 This example uses a genetic algorithm with multiple populations. initializing...evolving....................................................................................................... best individual is: 11111111111111111111111111111111 100 # current generation 1 # current convergence 13000 # number of selections since initialization 12500 # number of crossovers since initialization 12024 # number of mutations since initialization 12500 # number of replacements since initialization 12650 # number of genome evaluations since initialization 1005 # number of population evaluations since initialization 1 # maximum score since initialization 0 # minimum score since initialization 0.163021 # average of all scores ('on-line' performance) 0.984688 # average of maximum scores ('off-line' performance) 0 # average of minimum scores ('off-line' performance) 0.1125 # mean score in initial population 0.6875 # maximum score in initial population 0 # minimum score in initial population 0.255937 # standard deviation of initial population -1 # diversity of initial population (0=identical,-1=unset) 0.166667 # mean score in current population 1 # maximum score in current population 0 # minimum score in current population 0.379049 # standard deviation of current population -1 # diversity of current population (0=identical,-1=unset) 20 # how far back to look for convergence 1 # how often to record scores 0 # how often to write scores to file generations.dat # name of file to which scores are written Example 26 The Travelling Salesman Problem (TSP) demo program. initializing...evolving...10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 170 180 190 200 210 220 230 240 250 260 270 280 290 300 310 320 330 340 350 360 370 380 390 400 410 420 430 440 450 460 470 480 490 500 510 520 530 540 550 560 570 580 590 600 610 620 630 640 650 660 670 680 690 700 710 720 730 740 750 760 770 780 790 800 810 820 830 840 850 860 870 880 890 900 910 920 930 940 950 960 970 980 990 1000 the shortest path found is 22.6503 this is the distance from the sequence 5 6 10 14 18 19 15 11 7 3 2 1 20 0 4 8 12 16 17 13 9 1000 # current generation 1 # current convergence 100000 # number of selections since initialization 100000 # number of crossovers since initialization 10014 # number of mutations since initialization 100000 # number of replacements since initialization 100100 # number of genome evaluations since initialization 1001 # number of population evaluations since initialization 64.3227 # maximum score since initialization 22.6503 # minimum score since initialization 23.1627 # average of all scores ('on-line' performance) 23.2063 # average of maximum scores ('off-line' performance) 23.0545 # average of minimum scores ('off-line' performance) 54.0745 # mean score in initial population 64.3227 # maximum score in initial population 44.4397 # minimum score in initial population 4.07012 # standard deviation of initial population -1 # diversity of initial population (0=identical,-1=unset) 22.6503 # mean score in current population 22.6503 # maximum score in current population 22.6503 # minimum score in current population 2.66312e-06 # standard deviation of current population -1 # diversity of current population (0=identical,-1=unset) 20 # how far back to look for convergence 100 # how often to record scores 0 # how often to write scores to file generations.dat # name of file to which scores are written Example 27 Deterministic crowding demonstration program. In addition to the standard GAlib command-line arguments, you can specify one of the four following functions: 0 - modified Himmelblau's function 1 - Foxholes (25) 2 - Schwefel's nasty (1 glob. Max bei (420.96/420.96) 3 - Mexican Hat (optimum at 0,0) best individual is 3.00116 1.99599 100 # current generation 0.999999 # current convergence 10000 # number of selections since initialization 5000 # number of crossovers since initialization 245 # number of mutations since initialization 953 # number of replacements since initialization 5100 # number of genome evaluations since initialization 101 # number of population evaluations since initialization 10 # maximum score since initialization 5.06767 # minimum score since initialization 9.90808 # average of all scores ('on-line' performance) 9.99984 # average of maximum scores ('off-line' performance) 9.35658 # average of minimum scores ('off-line' performance) 8.84823 # mean score in initial population 9.99917 # maximum score in initial population 5.06767 # minimum score in initial population 1.05433 # standard deviation of initial population -1 # diversity of initial population (0=identical,-1=unset) 9.99484 # mean score in current population 10 # maximum score in current population 9.96593 # minimum score in current population 0.00755568 # standard deviation of current population -1 # diversity of current population (0=identical,-1=unset) 20 # how far back to look for convergence 100 # how often to record scores 0 # how often to write scores to file generations.dat # name of file to which scores are written galib247/examples/results/test_results-winnt.txt0100644003643600364360000006575710573535476021446 0ustar mwallmwallresults randtest.exe: Random Number Test Using the RAN2 random number generator (RNG). Using specified random seed 555 Library thinks the random seed is 555 running the chi-square test for randomness of the RNG... (there will be some failures of the chi-square test) integer test (1000): chi-squared should be within 20 of 100 run #0 93.2 run #1 101.52 run #2 119.752 run #3 103.175 run #4 130.718 ***failed*** run #5 118.672 run #6 93.8672 run #7 101.787 run #8 132.579 ***failed*** run #9 114.258 integer test (10000): chi-squared should be within 20 of 100 run #0 88.2 run #1 87.82 run #2 77.3 ***failed*** run #3 81.22 run #4 94.18 run #5 113.46 run #6 102.72 run #7 94.24 run #8 71.24 ***failed*** run #9 117.86 integer test (10000): chi-squared should be within 20 of 100 run #0 109.12 run #1 113.06 run #2 133.26 ***failed*** run #3 99.82 run #4 109.18 run #5 90.98 run #6 100.58 run #7 101.34 run #8 93.74 run #9 89.38 integer test (100000): chi-squared should be within 20 of 100 run #0 119.2 run #1 99.978 run #2 110.9 run #3 103.678 run #4 82.366 run #5 102.464 run #6 91.632 run #7 86.82 run #8 109.812 run #9 86.968 Example 1 This program tries to fill a 2DBinaryStringGenome with alternating 1s and 0s using a SimpleGA The GA found: 0101010101 1010101010 0101010101 1010101010 0101010101 Example 2 This program generates a sequence of random numbers then uses a simple GA and binary-to-decimal genome to match the sequence. input sequence: 0.265886 54.6261 3 -2.85019 69151.2 0.00150462 2 random values in the genome: 0.980392 18.4314 3 -4.34118 23997.6 0.00276471 0.494118 the ga generated: 0.278431 54.5098 3 -2.87059 2450.59 0.00163529 2.00392 best of generation data are in 'bog.dat' Example 3 This program reads in a data file then runs a simple GA whose objective function tries to match the pattern of bits that are in the data file. input pattern: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * best of generation data are in 'bog.dat' the ga generated: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Example 4 This program tries to fill a 3DBinaryStringGenome with alternating 1s and 0s using a SteadyStateGA the ga generated: 0101010101 1010101010 0101010101 1010101010 0101010101 1010101010 0101010101 1010101010 0101010101 1010101010 0101010101 1010101010 0101010101 1010101010 0101010101 best of generation data are in 'bog.dat' Example 5 This program shows how to use a composite genome. It reads a matrix from a data file and a set of values to be matched in a binary-to-decimal genome then uses a steady-state GA to match the pattern and value set. input pattern: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * input sequence: 10.2 32.5 66 99.234 0.003 210 the ga generated: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 8.3767 32.4286 55.2418 101.924 0.00209011 150.615 Example 6 This example uses a SteadyState GA and Tree genome. It tries to maximize the size of the tree genomes that it contains. The genomes contain ints in its nodes. 8653 nodes, 120 levels deep. best of generation data are in 'bog.dat' Example 7 This program reads in a data file then runs a steady-state GA whose objective function tries to match the pattern of bits that are in the data file. input pattern: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * the ga generated: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * best of generation data are in 'bog.dat' Example 8 This program runs a steady-state GA whose objective function tries to maximize the size of the list and tries to make lists that contain the number 101 in the nodes. The lists contain ints in the nodes. the list contains 0 nodes the ga used the parameters: minimaxi 1 number_of_generations 50 generations_to_convergence 20 convergence_percentage 0.99 crossover_probability 0.6 mutation_probability 0.05 population_size 40 score_frequency 1 flush_frequency 10 record_diversity 0 score_filename bog.dat select_scores 7 number_of_best 1 replacement_percentage 0.5 replacement_number 20 Example 9 This program finds the maximum value in the function y = - x1^2 - x2^2 with the constraints -5 <= x1 <= 5 -5 <= x2 <= 5 the ga found an optimum at the point (7.62951e-005, 0.00328069) best of generation data are in 'bog.dat' Example 10 This program uses sharing to do speciation. The objective function has more than one optimum, so different genomes may have equally high scores. Speciation keeps the population from clustering at one optimum. Both gene-wise and phenotype-wise distance functions are used. Populations from all three runs are written to the files pop.nospec.dat, pop.genespec.dat and pop.phenespec.dat. The function is written to the file sinusoid.dat running with no speciation (fitness proportionate scaling)... the ga found an optimum at the point 3.2549 running the ga with speciation (sharing using bit-wise)... the ga found an optimum at the point 2.2549 running the ga with speciation (sharing using phenotype-wise)... the ga found an optimum at the point 4.2549 dumping the function to file... Example 11 This program illustrates the use of order-based lists. The list in this problem contains 25 numbers, 0 to 24. It tries to put them in descending order from 24 to 0. the ga generated the following list (objective score is 24): 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 best of generation data are in 'bog.dat' minimaxi 1 number_of_generations 1000 generations_to_convergence 20 convergence_percentage 0.99 crossover_probability 0.6 mutation_probability 0.01 population_size 30 score_frequency 10 flush_frequency 10 record_diversity 0 score_filename bog.dat select_scores 2 number_of_best 1 replacement_percentage 0.5 replacement_number 15 Example 12 This program illustrates the use of order-based strings. The string in this problem contains 26 letters, a to z. It tries to put them in alphabetic order. the ga generated the following string (objective score is 26): abcdefghijklmnopqrstuvwxyz GAStringGenome Example 13 This program runs a GA-within-GA. The outer level GA tries to match the pattern read in from a file. The inner level GA is run only when the outer GA reaches a threshhold objective score then it tries to match a sequence of numbers that were generated randomly at the beginning of the program's execution. You might have to run the primary GA for more than 5000 generations to get a score high enough to kick in the secondary genetic algorithm. Use the ngen option to do this on the command line. input pattern: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * input sequence: 0.265886 54.6261 3 -2.85019 69151.2 0.00150462 2 the ga generated: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 0.411765 12.9412 3 -2.16471 74143.5 0.00749412 6.17647 best of generation data are in 'bog.dat' Example 14 This example shows how to create a genome that contains a list of lists. We create a composite genome that has lists in it. Each list has some nodes, only one of which contains the number 0. The objective is to move the node with number 0 in it to the nth position where n is the number of the list within the composite genome. a randomly-generated set of paths: list 0: 28 20 21 22 25 24 0 26 23 27 list 1: 22 20 23 21 0 24 25 26 28 27 list 2: 20 23 21 28 27 24 22 26 0 25 list 3: 0 20 21 22 23 24 27 26 25 28 list 4: 0 28 21 22 23 24 27 26 20 25 list 5: 28 27 21 26 23 24 25 22 20 0 the ga generated: list 0: 0 26 24 22 25 23 27 28 21 20 list 1: 24 0 20 26 23 22 25 27 21 28 list 2: 21 26 0 22 23 20 25 27 28 24 list 3: 24 21 22 0 23 27 25 20 26 28 list 4: 24 26 23 21 0 20 22 28 27 25 list 5: 20 26 21 25 23 0 24 22 27 28 Example 15 This program generates a sequence of random numbers then uses a simple GA and binary-to-decimal genome to match the sequence. It uses the convergence of the best-of-generation as the criterion for when to stop. input sequence: 0.265886 54.6261 3 -2.85019 69151.2 0.00150462 2 random values in the genome: 0.419608 85.098 3 -4.90588 6760 0.00834118 5.92941 the ga generated: 0.247059 49.8039 3 -2.74118 60823.5 0.00156471 2.00392 Example 16 This example uses a SteadyState GA and Tree genome. It tries to maximize the size of the tree genomes that it contains. The genomes contain points in its nodes. Two different runs are made: first with the swap subtree mutator, second with the destructive mutator. initializing...evolving for 10 generations............. the ga generated a tree with 37 nodes, 9 levels deep. initializing...evolving for 10 generations............. the ga generated a tree with 35 nodes, 12 levels deep. Example 17 This program illustrates the use of a 2DArrayGenome with three alleles. It tries to fill a 2D array with alternating 0s and 1s, and -1s at the corners. You will have to run it for something like 10000 generations to get the perfect score. evolving........................................................................................................................................................................................................... the ga generated: -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 Example 18 This program is designed to compare the GA types. You can specify steady-state, incremental, or simple GA and tweak any of the parameters for each of these GA types. The objective function tries to match a pattern read in from a file. input pattern: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * the ga generated: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * the statistics for the run are: 400 # current generation 0.990521 # current convergence 12000 # number of selections since initialization 10776 # number of crossovers since initialization 2707 # number of mutations since initialization 12000 # number of replacements since initialization 11051 # number of genome evaluations since initialization 201 # number of population evaluations since initialization 211 # maximum score since initialization 88 # minimum score since initialization 182.65 # average of all scores ('on-line' performance) 187.255 # average of maximum scores ('off-line' performance) 178.163 # average of minimum scores ('off-line' performance) 112.9 # mean score in initial population 127 # maximum score in initial population 88 # minimum score in initial population 7.63996 # standard deviation of initial population -1 # diversity of initial population (0=identical,-1=unset) 207.2 # mean score in current population 211 # maximum score in current population 203 # minimum score in current population 2.49689 # standard deviation of current population -1 # diversity of current population (0=identical,-1=unset) 20 # how far back to look for convergence 10 # how often to record scores 50 # how often to write scores to file bog.dat # name of file to which scores are written the objective function was called 11051 times best of generation data are in 'bog.dat' Example 19 This program runs the DeJong test problems. running DeJong function number 1 ... the ga generated: 5.11 -5.12 -5.12 the statistics for the run are: 400 # current generation 1 # current convergence 3200 # number of selections since initialization 2481 # number of crossovers since initialization 152 # number of mutations since initialization 2800 # number of replacements since initialization 2524 # number of genome evaluations since initialization 401 # number of population evaluations since initialization 78.5409 # maximum score since initialization 0.342654 # minimum score since initialization 77.4229 # average of all scores ('on-line' performance) 78.006 # average of maximum scores ('off-line' performance) 77.0203 # average of minimum scores ('off-line' performance) 25.943 # mean score in initial population 76.0281 # maximum score in initial population 0.342654 # minimum score in initial population 14.6341 # standard deviation of initial population -1 # diversity of initial population (0=identical,-1=unset) 78.5409 # mean score in current population 78.5409 # maximum score in current population 78.5409 # minimum score in current population 7.75982e-006 # standard deviation of current population -1 # diversity of current population (0=identical,-1=unset) 20 # how far back to look for convergence 10 # how often to record scores 50 # how often to write scores to file bog.dat # name of file to which scores are written best-of-generation data are in 'bog.dat' Example 20 Running Holland's Royal Road test problem with a genome that is 240 bits long (16 blocks). The parameters are as follows: block size: 8 gap size: 7 m*: 4 u*: 1 u: 0.3 v: 0.02 the ga generated: 110010100110101111111110100011010111000001101111111110010111011000111001011110001010011100111111111000101111111110110001100110011010111011110000011011011000110101000111111110111000101000111111001111111110011001001110010111101111111110101000 the highest level achieved was 1 the statistics for the run are: 10000 # current generation 1 # current convergence 2560000 # number of selections since initialization 2305756 # number of crossovers since initialization 613723 # number of mutations since initialization 2560000 # number of replacements since initialization 2360486 # number of genome evaluations since initialization 10001 # number of population evaluations since initialization 4.52 # maximum score since initialization -0.06 # minimum score since initialization 4.51623 # average of all scores ('on-line' performance) 4.51813 # average of maximum scores ('off-line' performance) 4.51554 # average of minimum scores ('off-line' performance) 0.541289 # mean score in initial population 1.9 # maximum score in initial population -0.06 # minimum score in initial population 0.303989 # standard deviation of initial population -1 # diversity of initial population (0=identical,-1=unset) 4.52001 # mean score in current population 4.52 # maximum score in current population 4.52 # minimum score in current population 1.38418e-005 # standard deviation of current population -1 # diversity of current population (0=identical,-1=unset) 20 # how far back to look for convergence 20 # how often to record scores 100 # how often to write scores to file bog.dat # name of file to which scores are written the parameters for the run are: minimaxi 1 number_of_generations 10000 generations_to_convergence 20 convergence_percentage 0.99 crossover_probability 0.9 mutation_probability 0.001 population_size 512 score_frequency 20 flush_frequency 100 record_diversity 0 score_filename bog.dat select_scores 2 number_of_best 1 replacement_percentage 0.5 replacement_number 256 Example 21 This example shows various uses of the allele set object in combination with the real number genome. running ga number 1 (alternate allele(0) and allele(3))... the ga generated: -10 10 -10 10 -10 10 -10 10 running ga number 2 (continuous descending order)... the ga generated: 0.722113 0.690404 0.475627 0.443254 0.413628 0.307699 0.286382 0.0776234 running ga number 2a (descending order, EXCLUSIVE)... the ga generated: 0.877096 0.635132 0.0272497 0.92776 0.512969 0.228361 0.17755 0.021867 running ga number 3 (discretized ascending order)... the ga generated: 2.5 3 4 4.5 6 7 9 9.5 running ga number 4 (maximize each gene)... the ga generated: 10 100 -5 -0.0001 11000 Example 22 This example shows how to derive your own genetic algorithm class. Here we use a custom, single-child crossover and a modified replacement strategy with overlapping populations. initializing... evolving.......... dumping the function to file... initial population is in 'pop.initial.dat' final population is in 'pop.final.dat' the function is in 'sinusoid.dat' parameters were: minimaxi 1 number_of_generations 500 generations_to_convergence 20 convergence_percentage 0.99 crossover_probability 1 mutation_probability 0.01 population_size 100 score_frequency 10 flush_frequency 100 record_diversity 0 score_filename bog.dat select_scores 255 number_of_best 1 replacement_percentage 0.25 replacement_number 25 Example 23 This program tries to maximize or minimize, depending on the command line argument that you give it. Use the command-line argument 'mm -1' to minimize (the default for this example), or 'mm 1' to maximize. The objective function is a simple sinusoidal. printing initial population to file... printing final population to file... printing function to file... Example 24 This example illustrates how to derive your own genetic algorithm. This genetic algorithm does restricted mating and uses a selector slightly more finicky than a uniform random selector. The objective function is a simple sinusoidal. printing population to file 'population.dat'... printing function to file 'sinusoid.dat'... Example 25 This example uses a genetic algorithm with multiple populations. initializing...evolving....................................................................................................... best individual is: 11111111111111111111111111111111 100 # current generation 1 # current convergence 13000 # number of selections since initialization 12500 # number of crossovers since initialization 12024 # number of mutations since initialization 12500 # number of replacements since initialization 12650 # number of genome evaluations since initialization 1005 # number of population evaluations since initialization 1 # maximum score since initialization 0 # minimum score since initialization 0.163021 # average of all scores ('on-line' performance) 0.984688 # average of maximum scores ('off-line' performance) 0 # average of minimum scores ('off-line' performance) 0.1125 # mean score in initial population 0.6875 # maximum score in initial population 0 # minimum score in initial population 0.255937 # standard deviation of initial population -1 # diversity of initial population (0=identical,-1=unset) 0.166667 # mean score in current population 1 # maximum score in current population 0 # minimum score in current population 0.379049 # standard deviation of current population -1 # diversity of current population (0=identical,-1=unset) 20 # how far back to look for convergence 1 # how often to record scores 0 # how often to write scores to file generations.dat # name of file to which scores are written Example 26 The Travelling Salesman Problem (TSP) demo program. initializing...evolving...10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 170 180 190 200 210 220 230 240 250 260 270 280 290 300 310 320 330 340 350 360 370 380 390 400 410 420 430 440 450 460 470 480 490 500 510 520 530 540 550 560 570 580 590 600 610 620 630 640 650 660 670 680 690 700 710 720 730 740 750 760 770 780 790 800 810 820 830 840 850 860 870 880 890 900 910 920 930 940 950 960 970 980 990 1000 the shortest path found is 22.6503 this is the distance from the sequence 5 6 10 14 18 19 15 11 7 3 2 1 20 0 4 8 12 16 17 13 9 1000 # current generation 1 # current convergence 100000 # number of selections since initialization 100000 # number of crossovers since initialization 10014 # number of mutations since initialization 100000 # number of replacements since initialization 100100 # number of genome evaluations since initialization 1001 # number of population evaluations since initialization 64.3227 # maximum score since initialization 22.6503 # minimum score since initialization 23.1626 # average of all scores ('on-line' performance) 23.2063 # average of maximum scores ('off-line' performance) 23.0545 # average of minimum scores ('off-line' performance) 54.0745 # mean score in initial population 64.3227 # maximum score in initial population 44.4397 # minimum score in initial population 4.07012 # standard deviation of initial population -1 # diversity of initial population (0=identical,-1=unset) 22.6503 # mean score in current population 22.6503 # maximum score in current population 22.6503 # minimum score in current population 2.66312e-006 # standard deviation of current population -1 # diversity of current population (0=identical,-1=unset) 20 # how far back to look for convergence 100 # how often to record scores 0 # how often to write scores to file generations.dat # name of file to which scores are written Example 27 Deterministic crowding demonstration program. In addition to the standard GAlib command-line arguments, you can specify one of the four following functions: 0 - modified Himmelblau's function 1 - Foxholes (25) 2 - Schwefel's nasty (1 glob. Max bei (420.96/420.96) 3 - Mexican Hat (optimum at 0,0) best individual is 2.99908 1.99542 100 # current generation 1 # current convergence 10000 # number of selections since initialization 5000 # number of crossovers since initialization 245 # number of mutations since initialization 971 # number of replacements since initialization 5100 # number of genome evaluations since initialization 101 # number of population evaluations since initialization 10 # maximum score since initialization 5.06767 # minimum score since initialization 9.90733 # average of all scores ('on-line' performance) 9.99984 # average of maximum scores ('off-line' performance) 9.30794 # average of minimum scores ('off-line' performance) 8.84823 # mean score in initial population 9.99917 # maximum score in initial population 5.06767 # minimum score in initial population 1.05433 # standard deviation of initial population -1 # diversity of initial population (0=identical,-1=unset) 9.99472 # mean score in current population 10 # maximum score in current population 9.95967 # minimum score in current population 0.0081183 # standard deviation of current population -1 # diversity of current population (0=identical,-1=unset) 20 # how far back to look for convergence 100 # how often to record scores 0 # how often to write scores to file generations.dat # name of file to which scores are written galib247/examples/results/test_stats-cygwin-x86.txt0100644003643600364360000000453510573535476021652 0ustar mwallmwall900MHz athlon win2k CYGWIN_NT-5.0 panela 1.5.12(0.116/4/2) 2004-11-10 08:34 i686 unknown unknown Cygwin randtest start: Tue Dec 28 19:14:16 EST 2004 finish: Tue Dec 28 19:14:18 EST 2004 ex1 start: Tue Dec 28 19:14:18 EST 2004 finish: Tue Dec 28 19:14:19 EST 2004 ex2 start: Tue Dec 28 19:14:19 EST 2004 finish: Tue Dec 28 19:14:20 EST 2004 ex3 start: Tue Dec 28 19:14:20 EST 2004 finish: Tue Dec 28 19:14:22 EST 2004 ex4 start: Tue Dec 28 19:14:22 EST 2004 finish: Tue Dec 28 19:14:23 EST 2004 ex5 start: Tue Dec 28 19:14:23 EST 2004 finish: Tue Dec 28 19:14:25 EST 2004 ex6 start: Tue Dec 28 19:14:25 EST 2004 finish: Tue Dec 28 19:14:53 EST 2004 ex7 start: Tue Dec 28 19:14:53 EST 2004 finish: Tue Dec 28 19:14:53 EST 2004 ex8 start: Tue Dec 28 19:14:53 EST 2004 finish: Tue Dec 28 19:14:54 EST 2004 ex9 start: Tue Dec 28 19:14:54 EST 2004 finish: Tue Dec 28 19:14:54 EST 2004 ex10 start: Tue Dec 28 19:14:54 EST 2004 finish: Tue Dec 28 19:14:57 EST 2004 ex11 start: Tue Dec 28 19:14:57 EST 2004 finish: Tue Dec 28 19:14:59 EST 2004 ex12 start: Tue Dec 28 19:14:59 EST 2004 finish: Tue Dec 28 19:15:00 EST 2004 ex13 start: Tue Dec 28 19:15:00 EST 2004 finish: Tue Dec 28 19:15:01 EST 2004 ex14 start: Tue Dec 28 19:15:01 EST 2004 finish: Tue Dec 28 19:15:02 EST 2004 ex15 start: Tue Dec 28 19:15:02 EST 2004 finish: Tue Dec 28 19:15:03 EST 2004 ex16 start: Tue Dec 28 19:15:03 EST 2004 finish: Tue Dec 28 19:15:03 EST 2004 ex17 start: Tue Dec 28 19:15:03 EST 2004 finish: Tue Dec 28 19:15:16 EST 2004 ex18 start: Tue Dec 28 19:15:16 EST 2004 finish: Tue Dec 28 19:15:17 EST 2004 ex19 start: Tue Dec 28 19:15:17 EST 2004 finish: Tue Dec 28 19:15:18 EST 2004 ex20 start: Tue Dec 28 19:15:18 EST 2004 finish: Tue Dec 28 19:18:08 EST 2004 ex21 start: Tue Dec 28 19:18:08 EST 2004 finish: Tue Dec 28 19:18:10 EST 2004 ex22 start: Tue Dec 28 19:18:10 EST 2004 finish: Tue Dec 28 19:18:15 EST 2004 ex23 start: Tue Dec 28 19:18:15 EST 2004 finish: Tue Dec 28 19:18:15 EST 2004 ex24 start: Tue Dec 28 19:18:15 EST 2004 finish: Tue Dec 28 19:18:16 EST 2004 ex25 start: Tue Dec 28 19:18:16 EST 2004 finish: Tue Dec 28 19:18:16 EST 2004 ex26 start: Tue Dec 28 19:18:16 EST 2004 finish: Tue Dec 28 19:18:52 EST 2004 ex27 start: Tue Dec 28 19:18:52 EST 2004 finish: Tue Dec 28 19:18:53 EST 2004 galib247/examples/results/test_stats-hpux11.txt0100644003643600364360000000450510573535476021052 0ustar mwallmwallhp visualize c240 HP-UX testouri B.11.00 A 9000/782 2008476391 two-user license randtest start: Tue Dec 28 17:36:31 EST 2004 finish: Tue Dec 28 17:36:35 EST 2004 ex1 start: Tue Dec 28 17:36:35 EST 2004 finish: Tue Dec 28 17:36:38 EST 2004 ex2 start: Tue Dec 28 17:36:38 EST 2004 finish: Tue Dec 28 17:36:38 EST 2004 ex3 start: Tue Dec 28 17:36:38 EST 2004 finish: Tue Dec 28 17:36:49 EST 2004 ex4 start: Tue Dec 28 17:36:49 EST 2004 finish: Tue Dec 28 17:36:56 EST 2004 ex5 start: Tue Dec 28 17:36:56 EST 2004 finish: Tue Dec 28 17:37:05 EST 2004 ex6 start: Tue Dec 28 17:37:05 EST 2004 finish: Tue Dec 28 17:37:58 EST 2004 ex7 start: Tue Dec 28 17:37:58 EST 2004 finish: Tue Dec 28 17:38:03 EST 2004 ex8 start: Tue Dec 28 17:38:03 EST 2004 finish: Tue Dec 28 17:38:03 EST 2004 ex9 start: Tue Dec 28 17:38:03 EST 2004 finish: Tue Dec 28 17:38:04 EST 2004 ex10 start: Tue Dec 28 17:38:04 EST 2004 finish: Tue Dec 28 17:38:16 EST 2004 ex11 start: Tue Dec 28 17:38:16 EST 2004 finish: Tue Dec 28 17:38:20 EST 2004 ex12 start: Tue Dec 28 17:38:20 EST 2004 finish: Tue Dec 28 17:38:27 EST 2004 ex13 start: Tue Dec 28 17:38:27 EST 2004 finish: Tue Dec 28 17:38:28 EST 2004 ex14 start: Tue Dec 28 17:38:28 EST 2004 finish: Tue Dec 28 17:38:32 EST 2004 ex15 start: Tue Dec 28 17:38:32 EST 2004 finish: Tue Dec 28 17:38:32 EST 2004 ex16 start: Tue Dec 28 17:38:33 EST 2004 finish: Tue Dec 28 17:38:33 EST 2004 ex17 start: Tue Dec 28 17:38:33 EST 2004 finish: Tue Dec 28 17:41:14 EST 2004 ex18 start: Tue Dec 28 17:41:14 EST 2004 finish: Tue Dec 28 17:41:25 EST 2004 ex19 start: Tue Dec 28 17:41:25 EST 2004 finish: Tue Dec 28 17:41:26 EST 2004 ex20 start: Tue Dec 28 17:41:26 EST 2004 finish: Tue Dec 28 18:18:34 EST 2004 ex21 start: Tue Dec 28 18:18:34 EST 2004 finish: Tue Dec 28 18:18:44 EST 2004 ex22 start: Tue Dec 28 18:18:44 EST 2004 finish: Tue Dec 28 18:19:09 EST 2004 ex23 start: Tue Dec 28 18:19:09 EST 2004 finish: Tue Dec 28 18:19:09 EST 2004 ex24 start: Tue Dec 28 18:19:09 EST 2004 finish: Tue Dec 28 18:19:10 EST 2004 ex25 start: Tue Dec 28 18:19:10 EST 2004 finish: Tue Dec 28 18:19:12 EST 2004 ex26 start: Tue Dec 28 18:19:12 EST 2004 finish: Tue Dec 28 18:20:17 EST 2004 ex27 start: Tue Dec 28 18:20:17 EST 2004 finish: Tue Dec 28 18:20:17 EST 2004 galib247/examples/results/test_stats-irix.txt0100644003643600364360000000442410573535476020677 0ustar mwallmwallIRIX64 sirene 6.5 10120733 IP30 randtest start: Tue Dec 28 21:07:58 EST 2004 finish: Tue Dec 28 21:07:59 EST 2004 ex1 start: Tue Dec 28 21:07:59 EST 2004 finish: Tue Dec 28 21:08:01 EST 2004 ex2 start: Tue Dec 28 21:08:01 EST 2004 finish: Tue Dec 28 21:08:01 EST 2004 ex3 start: Tue Dec 28 21:08:01 EST 2004 finish: Tue Dec 28 21:08:05 EST 2004 ex4 start: Tue Dec 28 21:08:05 EST 2004 finish: Tue Dec 28 21:08:08 EST 2004 ex5 start: Tue Dec 28 21:08:08 EST 2004 finish: Tue Dec 28 21:08:14 EST 2004 ex6 start: Tue Dec 28 21:08:14 EST 2004 finish: Tue Dec 28 21:08:53 EST 2004 ex7 start: Tue Dec 28 21:08:53 EST 2004 finish: Tue Dec 28 21:08:55 EST 2004 ex8 start: Tue Dec 28 21:08:55 EST 2004 finish: Tue Dec 28 21:08:55 EST 2004 ex9 start: Tue Dec 28 21:08:55 EST 2004 finish: Tue Dec 28 21:08:55 EST 2004 ex10 start: Tue Dec 28 21:08:55 EST 2004 finish: Tue Dec 28 21:09:07 EST 2004 ex11 start: Tue Dec 28 21:09:07 EST 2004 finish: Tue Dec 28 21:09:10 EST 2004 ex12 start: Tue Dec 28 21:09:10 EST 2004 finish: Tue Dec 28 21:09:15 EST 2004 ex13 start: Tue Dec 28 21:09:15 EST 2004 finish: Tue Dec 28 21:09:16 EST 2004 ex14 start: Tue Dec 28 21:09:16 EST 2004 finish: Tue Dec 28 21:09:18 EST 2004 ex15 start: Tue Dec 28 21:09:18 EST 2004 finish: Tue Dec 28 21:09:18 EST 2004 ex16 start: Tue Dec 28 21:09:18 EST 2004 finish: Tue Dec 28 21:09:19 EST 2004 ex17 start: Tue Dec 28 21:09:19 EST 2004 finish: Tue Dec 28 21:10:25 EST 2004 ex18 start: Tue Dec 28 21:10:25 EST 2004 finish: Tue Dec 28 21:10:30 EST 2004 ex19 start: Tue Dec 28 21:10:30 EST 2004 finish: Tue Dec 28 21:10:30 EST 2004 ex20 start: Tue Dec 28 21:10:30 EST 2004 finish: Tue Dec 28 21:24:53 EST 2004 ex21 start: Tue Dec 28 21:24:53 EST 2004 finish: Tue Dec 28 21:25:00 EST 2004 ex22 start: Tue Dec 28 21:25:00 EST 2004 finish: Tue Dec 28 21:25:13 EST 2004 ex23 start: Tue Dec 28 21:25:13 EST 2004 finish: Tue Dec 28 21:25:13 EST 2004 ex24 start: Tue Dec 28 21:25:13 EST 2004 finish: Tue Dec 28 21:25:13 EST 2004 ex25 start: Tue Dec 28 21:25:13 EST 2004 finish: Tue Dec 28 21:25:14 EST 2004 ex26 start: Tue Dec 28 21:25:14 EST 2004 finish: Tue Dec 28 21:25:58 EST 2004 ex27 start: Tue Dec 28 21:25:58 EST 2004 finish: Tue Dec 28 21:25:58 EST 2004 galib247/examples/results/test_stats-linux-ppc.txt0100644003643600364360000000455210573535476021645 0ustar mwallmwallpowermac g3 400MHz yellow dog linux 3 Linux gammelost 2.4.22-2f #1 Sun Nov 9 16:49:49 EST 2003 ppc ppc ppc GNU/Linux randtest start: Tue Dec 28 22:52:17 EST 2004 finish: Tue Dec 28 22:52:18 EST 2004 ex1 start: Tue Dec 28 22:52:18 EST 2004 finish: Tue Dec 28 22:52:19 EST 2004 ex2 start: Tue Dec 28 22:52:19 EST 2004 finish: Tue Dec 28 22:52:19 EST 2004 ex3 start: Tue Dec 28 22:52:19 EST 2004 finish: Tue Dec 28 22:52:21 EST 2004 ex4 start: Tue Dec 28 22:52:21 EST 2004 finish: Tue Dec 28 22:52:23 EST 2004 ex5 start: Tue Dec 28 22:52:23 EST 2004 finish: Tue Dec 28 22:52:26 EST 2004 ex6 start: Tue Dec 28 22:52:26 EST 2004 finish: Tue Dec 28 22:52:54 EST 2004 ex7 start: Tue Dec 28 22:52:54 EST 2004 finish: Tue Dec 28 22:52:55 EST 2004 ex8 start: Tue Dec 28 22:52:55 EST 2004 finish: Tue Dec 28 22:52:55 EST 2004 ex9 start: Tue Dec 28 22:52:55 EST 2004 finish: Tue Dec 28 22:52:56 EST 2004 ex10 start: Tue Dec 28 22:52:56 EST 2004 finish: Tue Dec 28 22:53:03 EST 2004 ex11 start: Tue Dec 28 22:53:03 EST 2004 finish: Tue Dec 28 22:53:05 EST 2004 ex12 start: Tue Dec 28 22:53:05 EST 2004 finish: Tue Dec 28 22:53:07 EST 2004 ex13 start: Tue Dec 28 22:53:07 EST 2004 finish: Tue Dec 28 22:53:08 EST 2004 ex14 start: Tue Dec 28 22:53:08 EST 2004 finish: Tue Dec 28 22:53:09 EST 2004 ex15 start: Tue Dec 28 22:53:09 EST 2004 finish: Tue Dec 28 22:53:10 EST 2004 ex16 start: Tue Dec 28 22:53:10 EST 2004 finish: Tue Dec 28 22:53:10 EST 2004 ex17 start: Tue Dec 28 22:53:10 EST 2004 finish: Tue Dec 28 22:53:43 EST 2004 ex18 start: Tue Dec 28 22:53:43 EST 2004 finish: Tue Dec 28 22:53:45 EST 2004 ex19 start: Tue Dec 28 22:53:45 EST 2004 finish: Tue Dec 28 22:53:46 EST 2004 ex20 start: Tue Dec 28 22:53:46 EST 2004 finish: Tue Dec 28 23:01:15 EST 2004 ex21 start: Tue Dec 28 23:01:15 EST 2004 finish: Tue Dec 28 23:01:19 EST 2004 ex22 start: Tue Dec 28 23:01:19 EST 2004 finish: Tue Dec 28 23:01:29 EST 2004 ex23 start: Tue Dec 28 23:01:29 EST 2004 finish: Tue Dec 28 23:01:29 EST 2004 ex24 start: Tue Dec 28 23:01:29 EST 2004 finish: Tue Dec 28 23:01:29 EST 2004 ex25 start: Tue Dec 28 23:01:29 EST 2004 finish: Tue Dec 28 23:01:30 EST 2004 ex26 start: Tue Dec 28 23:01:30 EST 2004 finish: Tue Dec 28 23:01:54 EST 2004 ex27 start: Tue Dec 28 23:01:54 EST 2004 finish: Tue Dec 28 23:01:55 EST 2004 galib247/examples/results/test_stats-linux-x86.txt0100644003643600364360000000454110573535476021506 0ustar mwallmwallintel dual 800MHz P3 Linux manur 2.6.5-1.358smp #1 SMP Sat May 8 09:25:36 EDT 2004 i686 i686 i386 GNU/Linux randtest start: Tue Dec 28 18:35:53 EST 2004 finish: Tue Dec 28 18:35:54 EST 2004 ex1 start: Tue Dec 28 18:35:54 EST 2004 finish: Tue Dec 28 18:35:55 EST 2004 ex2 start: Tue Dec 28 18:35:55 EST 2004 finish: Tue Dec 28 18:35:55 EST 2004 ex3 start: Tue Dec 28 18:35:55 EST 2004 finish: Tue Dec 28 18:35:56 EST 2004 ex4 start: Tue Dec 28 18:35:56 EST 2004 finish: Tue Dec 28 18:35:57 EST 2004 ex5 start: Tue Dec 28 18:35:57 EST 2004 finish: Tue Dec 28 18:35:58 EST 2004 ex6 start: Tue Dec 28 18:35:58 EST 2004 finish: Tue Dec 28 18:36:10 EST 2004 ex7 start: Tue Dec 28 18:36:10 EST 2004 finish: Tue Dec 28 18:36:11 EST 2004 ex8 start: Tue Dec 28 18:36:11 EST 2004 finish: Tue Dec 28 18:36:11 EST 2004 ex9 start: Tue Dec 28 18:36:11 EST 2004 finish: Tue Dec 28 18:36:11 EST 2004 ex10 start: Tue Dec 28 18:36:11 EST 2004 finish: Tue Dec 28 18:36:14 EST 2004 ex11 start: Tue Dec 28 18:36:14 EST 2004 finish: Tue Dec 28 18:36:14 EST 2004 ex12 start: Tue Dec 28 18:36:14 EST 2004 finish: Tue Dec 28 18:36:16 EST 2004 ex13 start: Tue Dec 28 18:36:16 EST 2004 finish: Tue Dec 28 18:36:16 EST 2004 ex14 start: Tue Dec 28 18:36:16 EST 2004 finish: Tue Dec 28 18:36:17 EST 2004 ex15 start: Tue Dec 28 18:36:17 EST 2004 finish: Tue Dec 28 18:36:17 EST 2004 ex16 start: Tue Dec 28 18:36:17 EST 2004 finish: Tue Dec 28 18:36:17 EST 2004 ex17 start: Tue Dec 28 18:36:17 EST 2004 finish: Tue Dec 28 18:36:33 EST 2004 ex18 start: Tue Dec 28 18:36:33 EST 2004 finish: Tue Dec 28 18:36:34 EST 2004 ex19 start: Tue Dec 28 18:36:34 EST 2004 finish: Tue Dec 28 18:36:34 EST 2004 ex20 start: Tue Dec 28 18:36:34 EST 2004 finish: Tue Dec 28 18:40:23 EST 2004 ex21 start: Tue Dec 28 18:40:23 EST 2004 finish: Tue Dec 28 18:40:24 EST 2004 ex22 start: Tue Dec 28 18:40:24 EST 2004 finish: Tue Dec 28 18:40:28 EST 2004 ex23 start: Tue Dec 28 18:40:28 EST 2004 finish: Tue Dec 28 18:40:29 EST 2004 ex24 start: Tue Dec 28 18:40:29 EST 2004 finish: Tue Dec 28 18:40:29 EST 2004 ex25 start: Tue Dec 28 18:40:29 EST 2004 finish: Tue Dec 28 18:40:29 EST 2004 ex26 start: Tue Dec 28 18:40:29 EST 2004 finish: Tue Dec 28 18:40:40 EST 2004 ex27 start: Tue Dec 28 18:40:40 EST 2004 finish: Tue Dec 28 18:40:40 EST 2004 galib247/examples/results/test_stats-macosx-gcc2.txt0100644003643600364360000000464410573535476022036 0ustar mwallmwallpowerbook g4 1.3GHz 1.3G ram Darwin gouda.local 7.7.0 Darwin Kernel Version 7.7.0: Sun Nov 7 16:06:51 PST 2004; root:xnu/xnu-517.9.5.obj~1/RELEASE_PPC Power Macintosh powerpc randtest start: Tue Dec 28 17:47:40 EST 2004 finish: Tue Dec 28 17:47:41 EST 2004 ex1 start: Tue Dec 28 17:47:41 EST 2004 finish: Tue Dec 28 17:47:41 EST 2004 ex2 start: Tue Dec 28 17:47:41 EST 2004 finish: Tue Dec 28 17:47:41 EST 2004 ex3 start: Tue Dec 28 17:47:41 EST 2004 finish: Tue Dec 28 17:47:43 EST 2004 ex4 start: Tue Dec 28 17:47:43 EST 2004 finish: Tue Dec 28 17:47:43 EST 2004 ex5 start: Tue Dec 28 17:47:43 EST 2004 finish: Tue Dec 28 17:47:45 EST 2004 ex6 start: Tue Dec 28 17:47:45 EST 2004 finish: Tue Dec 28 17:47:58 EST 2004 ex7 start: Tue Dec 28 17:47:58 EST 2004 finish: Tue Dec 28 17:47:58 EST 2004 ex8 start: Tue Dec 28 17:47:58 EST 2004 finish: Tue Dec 28 17:47:58 EST 2004 ex9 start: Tue Dec 28 17:47:58 EST 2004 finish: Tue Dec 28 17:47:59 EST 2004 ex10 start: Tue Dec 28 17:47:59 EST 2004 finish: Tue Dec 28 17:48:02 EST 2004 ex11 start: Tue Dec 28 17:48:02 EST 2004 finish: Tue Dec 28 17:48:03 EST 2004 ex12 start: Tue Dec 28 17:48:03 EST 2004 finish: Tue Dec 28 17:48:04 EST 2004 ex13 start: Tue Dec 28 17:48:04 EST 2004 finish: Tue Dec 28 17:48:04 EST 2004 ex14 start: Tue Dec 28 17:48:04 EST 2004 finish: Tue Dec 28 17:48:05 EST 2004 ex15 start: Tue Dec 28 17:48:05 EST 2004 finish: Tue Dec 28 17:48:05 EST 2004 ex16 start: Tue Dec 28 17:48:05 EST 2004 finish: Tue Dec 28 17:48:05 EST 2004 ex17 start: Tue Dec 28 17:48:05 EST 2004 finish: Tue Dec 28 17:48:17 EST 2004 ex18 start: Tue Dec 28 17:48:17 EST 2004 finish: Tue Dec 28 17:48:19 EST 2004 ex19 start: Tue Dec 28 17:48:19 EST 2004 finish: Tue Dec 28 17:48:19 EST 2004 ex20 start: Tue Dec 28 17:48:19 EST 2004 finish: Tue Dec 28 17:56:04 EST 2004 ex21 start: Tue Dec 28 17:56:04 EST 2004 finish: Tue Dec 28 17:56:06 EST 2004 ex22 start: Tue Dec 28 17:56:06 EST 2004 finish: Tue Dec 28 17:56:09 EST 2004 ex23 start: Tue Dec 28 17:56:09 EST 2004 finish: Tue Dec 28 17:56:09 EST 2004 ex24 start: Tue Dec 28 17:56:09 EST 2004 finish: Tue Dec 28 17:56:10 EST 2004 ex25 start: Tue Dec 28 17:56:10 EST 2004 finish: Tue Dec 28 17:56:10 EST 2004 ex26 start: Tue Dec 28 17:56:10 EST 2004 finish: Tue Dec 28 17:56:21 EST 2004 ex27 start: Tue Dec 28 17:56:21 EST 2004 finish: Tue Dec 28 17:56:21 EST 2004 galib247/examples/results/test_stats-macosx-gcc3.txt0100644003643600364360000000464410573535476022037 0ustar mwallmwallpowerbook g4 1.3GHz 1.3G ram Darwin gouda.local 7.7.0 Darwin Kernel Version 7.7.0: Sun Nov 7 16:06:51 PST 2004; root:xnu/xnu-517.9.5.obj~1/RELEASE_PPC Power Macintosh powerpc randtest start: Tue Dec 28 18:01:41 EST 2004 finish: Tue Dec 28 18:01:42 EST 2004 ex1 start: Tue Dec 28 18:01:42 EST 2004 finish: Tue Dec 28 18:01:43 EST 2004 ex2 start: Tue Dec 28 18:01:43 EST 2004 finish: Tue Dec 28 18:01:43 EST 2004 ex3 start: Tue Dec 28 18:01:43 EST 2004 finish: Tue Dec 28 18:01:45 EST 2004 ex4 start: Tue Dec 28 18:01:45 EST 2004 finish: Tue Dec 28 18:01:46 EST 2004 ex5 start: Tue Dec 28 18:01:46 EST 2004 finish: Tue Dec 28 18:01:48 EST 2004 ex6 start: Tue Dec 28 18:01:48 EST 2004 finish: Tue Dec 28 18:02:02 EST 2004 ex7 start: Tue Dec 28 18:02:02 EST 2004 finish: Tue Dec 28 18:02:02 EST 2004 ex8 start: Tue Dec 28 18:02:02 EST 2004 finish: Tue Dec 28 18:02:03 EST 2004 ex9 start: Tue Dec 28 18:02:03 EST 2004 finish: Tue Dec 28 18:02:03 EST 2004 ex10 start: Tue Dec 28 18:02:03 EST 2004 finish: Tue Dec 28 18:02:07 EST 2004 ex11 start: Tue Dec 28 18:02:07 EST 2004 finish: Tue Dec 28 18:02:08 EST 2004 ex12 start: Tue Dec 28 18:02:08 EST 2004 finish: Tue Dec 28 18:02:09 EST 2004 ex13 start: Tue Dec 28 18:02:09 EST 2004 finish: Tue Dec 28 18:02:10 EST 2004 ex14 start: Tue Dec 28 18:02:10 EST 2004 finish: Tue Dec 28 18:02:11 EST 2004 ex15 start: Tue Dec 28 18:02:11 EST 2004 finish: Tue Dec 28 18:02:11 EST 2004 ex16 start: Tue Dec 28 18:02:11 EST 2004 finish: Tue Dec 28 18:02:12 EST 2004 ex17 start: Tue Dec 28 18:02:12 EST 2004 finish: Tue Dec 28 18:02:26 EST 2004 ex18 start: Tue Dec 28 18:02:26 EST 2004 finish: Tue Dec 28 18:02:27 EST 2004 ex19 start: Tue Dec 28 18:02:27 EST 2004 finish: Tue Dec 28 18:02:27 EST 2004 ex20 start: Tue Dec 28 18:02:27 EST 2004 finish: Tue Dec 28 18:05:32 EST 2004 ex21 start: Tue Dec 28 18:05:32 EST 2004 finish: Tue Dec 28 18:05:34 EST 2004 ex22 start: Tue Dec 28 18:05:34 EST 2004 finish: Tue Dec 28 18:05:38 EST 2004 ex23 start: Tue Dec 28 18:05:38 EST 2004 finish: Tue Dec 28 18:05:39 EST 2004 ex24 start: Tue Dec 28 18:05:39 EST 2004 finish: Tue Dec 28 18:05:39 EST 2004 ex25 start: Tue Dec 28 18:05:39 EST 2004 finish: Tue Dec 28 18:05:40 EST 2004 ex26 start: Tue Dec 28 18:05:40 EST 2004 finish: Tue Dec 28 18:05:53 EST 2004 ex27 start: Tue Dec 28 18:05:53 EST 2004 finish: Tue Dec 28 18:05:53 EST 2004 galib247/examples/results/test_stats-win2k.txt0100644003643600364360000000361410573535476020756 0ustar mwallmwall900MHz athlon win2k sp4 stats randtest.exe Tue 12/28/2004 20:10:48.98 Tue 12/28/2004 20:10:50.23 ex1.exe Tue 12/28/2004 20:10:50.47 Tue 12/28/2004 20:10:51.42 ex2.exe Tue 12/28/2004 20:10:51.66 Tue 12/28/2004 20:10:52.28 ex3.exe Tue 12/28/2004 20:10:52.59 Tue 12/28/2004 20:10:54.33 ex4.exe Tue 12/28/2004 20:10:54.66 Tue 12/28/2004 20:10:55.99 ex5.exe Tue 12/28/2004 20:10:56.41 Tue 12/28/2004 20:10:58.68 ex6.exe Tue 12/28/2004 20:10:58.74 Tue 12/28/2004 20:11:47.97 ex7.exe Tue 12/28/2004 20:11:48.04 Tue 12/28/2004 20:11:48.71 ex8.exe Tue 12/28/2004 20:11:48.77 Tue 12/28/2004 20:11:48.99 ex9.exe Tue 12/28/2004 20:11:49.05 Tue 12/28/2004 20:11:49.28 ex10.exe Tue 12/28/2004 20:11:49.34 Tue 12/28/2004 20:11:52.71 ex11.exe Tue 12/28/2004 20:11:52.77 Tue 12/28/2004 20:11:54.32 ex12.exe Tue 12/28/2004 20:11:54.38 Tue 12/28/2004 20:11:55.85 ex13.exe Tue 12/28/2004 20:11:55.91 Tue 12/28/2004 20:11:56.37 ex14.exe Tue 12/28/2004 20:11:56.42 Tue 12/28/2004 20:11:58.02 ex15.exe Tue 12/28/2004 20:11:58.07 Tue 12/28/2004 20:11:58.26 ex16.exe Tue 12/28/2004 20:11:58.31 Tue 12/28/2004 20:11:58.47 ex17.exe Tue 12/28/2004 20:11:58.52 Tue 12/28/2004 20:12:17.14 ex18.exe Tue 12/28/2004 20:12:17.19 Tue 12/28/2004 20:12:18.53 ex19.exe Tue 12/28/2004 20:12:18.59 Tue 12/28/2004 20:12:18.83 ex20.exe Tue 12/28/2004 20:12:18.89 Tue 12/28/2004 20:16:32.43 ex21.exe Tue 12/28/2004 20:16:32.48 Tue 12/28/2004 20:16:34.46 ex22.exe Tue 12/28/2004 20:16:34.51 Tue 12/28/2004 20:16:39.48 ex23.exe Tue 12/28/2004 20:16:39.53 Tue 12/28/2004 20:16:39.76 ex24.exe Tue 12/28/2004 20:16:39.82 Tue 12/28/2004 20:16:40.14 ex25.exe Tue 12/28/2004 20:16:40.19 Tue 12/28/2004 20:16:40.63 ex26.exe Tue 12/28/2004 20:16:40.68 Tue 12/28/2004 20:17:02.82 ex27.exe Tue 12/28/2004 20:17:02.87 Tue 12/28/2004 20:17:03.11 galib247/examples/seed.C0100644003643600364360000001043710573535500014300 0ustar mwallmwall/* ---------------------------------------------------------------------------- seed.C mbwall 16nov98 ---------------------------------------------------------------------------- */ #include #include #include #include #define cout STD_COUT #define cerr STD_CERR #define ifstream STD_IFSTREAM float objective(GAGenome &); int main(int argc, char *argv[]) { cout << "Random Seed Test\n\n"; cout << "This program does three runs of a genetic algorithm, with the \n"; cout << "random seed resetting between each run. Each of the three runs \n"; cout << "should be identical\n\n"; cout.flush(); GAParameterList params; GASteadyStateGA::registerDefaultParameters(params); params.set(gaNnGenerations, 100); params.set(gaNflushFrequency, 5); params.set(gaNpMutation, 0.001); params.set(gaNpCrossover, 0.8); params.parse(argc, argv, gaFalse); int i,j; char filename[128] = "smiley.txt"; unsigned int seed=0; for(i=1; i= argc){ cerr << argv[0] << ": the file option needs a filename.\n"; exit(1); } else{ sprintf(filename, argv[i]); continue; } } else if(strcmp("seed", argv[i]) == 0){ if(++i >= argc){ cerr << argv[0] << ": the seed option needs a filename.\n"; exit(1); } else { seed = atoi(argv[i]); continue; } } else { cerr << argv[0] << ": unrecognized arguement: " << argv[i] << "\n\n"; cerr << "valid arguments include standard GAlib arguments plus:\n"; cerr << " f\tfilename from which to read (" << filename << ")\n"; cerr << "\n"; exit(1); } } const int n=5; cout << n << " random numbers\n"; GAResetRNG(seed); for(i=0; i> height >> width; short **target = new short*[width]; for(i=0; i> target[i][j]; inStream.close(); GA2DBinaryStringGenome genome(width, height, objective, (void *)target); GASimpleGA ga(genome); ga.parameters(params); // first run GAResetRNG(seed); genome.initialize(); cout << genome << "\n"; ga.set(gaNscoreFilename, "bog1.dat"); ga.evolve(); genome = ga.statistics().bestIndividual(); cout << "run 1: the random seed is: " << GAGetRandomSeed() << "\n"; for(j=0; j * gaconfig.h: added instantiation prefix for compilers that need forced instantiations but vary in their syntax. 2005-01-12 Matthew Wall * gaconfig.h: fixed comment about use of streams. keep MSC_VER detection after other compilers so that the windows- based compilers that are trying to be like vcpp will not be detected as vcpp. 2005-01-11 Matthew Wall * gaconfig.h: fixed macro definitions for streams, templates 2005-01-06 Matthew Wall * gaconfig.h: update ms compiler notes fixed borland compiler version detection. 2004-12-29 Matthew Wall * GA2DArrayGenome.C: fixed oversight * GASimpleGA.C: use our own seed if one was specified * GAPopulation.C: keep compilers happy about redefining NOMINMAX * gaversion.h: added function for programmatic access to the library identifier string. * GABaseGA.[hC]: added seed as a recognized option * ga.h: no need to remove the deterministic crowding algorithm - it has no templates. 2004-12-28 Matthew Wall * GAPopulation.C: be sure that we use the same score (just in case the invocation of the score member is not deterministic). * gaconfig.h: deal with assertions * GASelector.C: fix end-of-array bug and added assertions to trigger other bad index problems. 2004-12-28 Matthew Wall * GARealGenome.C: adhere to c++ standard * GAStringGenome.C: adhere to c++ standard * GAListGenome.C: adhere to c++ standard * GATreeGenome.C: adhere to c++ standard * GA3DArrayGenome.C: adhere to c++ standard * GA3DArrayGenome.h: adhere to c++ standard * GA2DArrayGenome.h: adhere to c++ standard * GA1DArrayGenome.C: adhere to c++ standard * GA1DArrayGenome.h: adhere to c++ standard * gabincvt.C: keep the compilers happy about conversions 2004-12-28 Matthew Wall * gaconfig.h: added options for ibm xlC and hp aCC compilers. * GARealGenome.h: adjust instantiation sequence to prevent premature instantiation (before specialization). esp for gcc3. * GAStringGenome.h: ditto * garandom.C: avoid naming clashes. eventually galib will live in its own namespace, but not for now. * garandom.h: dito * GARealGenome.C: fix specializations * GAStringGenome.C: fix specializations * makefile: added ranlib for macosx, aix emit compile flags to BUILD file for diagnosis. 2004-12-27 Matthew Wall * GAGenome.h: macro name change for streams management. include a separate file for streams. * GATreeGenome.C: ditto * GAStringGenome.C: ditto * GAStatistics.C: ditto * GARealGenome.C: ditto * GAPopulation.C: ditto * GAParameter.C: ditto * GAListGenome.C: ditto * GABin2DecGenome.C: ditto * GABaseGA.C: ditto * GAAllele.C: ditto * GA3DArrayGenome.C: ditto * GA3DBinStrGenome.C: ditto * GA2DBinStrGenome.C: ditto * GA2DArrayGenome.C: ditto * GA1DArrayGenome.C: ditto * GA1DBinStrGenome.C: ditto * gaerror.h: ditto * GAStatistics.h: ditto * GASimpleGA.h: ditto * GASStateGA.h: ditto * GAPopulation.h: ditto * GAParameter.h: ditto * GANode.h: ditto * GADemeGA.h: ditto * GAIncGA.h: ditto * GA2DBinStrGenome.h: ditto * GABin2DecGenome.h: ditto * GAListGenome.h: ditto * GATreeGenome.h: ditto * GABaseGA.h: ditto * GAAllele.h: ditto * GA3DBinStrGenome.h: ditto * GA3DArrayGenome.h: ditto * GA2DBinStrGenome.h: ditto * GA2DArrayGenome.h: ditto * GA1DBinStrGenome.h: ditto * GA1DArrayGenome.h: macro name change for streams management * ga.h: macro name change * std_stream.h: split stream inclusion into file separate from gaconfig in order to avoid clashes with 'using namespace std' * gaconfig.h: renamed macros to avoid clashes with other libraries and to make it easier to enable/disable features when tweaking galib to work with oddball compilers and environments. * gabincvt.C: use renamed macros * garandom.C: change to USE_PID macro * gaversion.h: added os-cpu-compiler detection to make identification of binaries bit easier using strings or ident. also the first step toward autoconf-style automatic detection of stuff (hopefully without all of the autoconf/automake overhead and failures). galib247/ga/ga.h0100644003643600364360000002074110573535474012576 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- ga.h mbwall 28jul94 Copyright (c) 1995-1996 Massachusetts Institute of Technology all rights reserved Main header for the GAlibrary. This header is provided to make it easy to include GAlib components in your code. It includes all of the genetic algorithm classes as well as all of the genome classes (plus a bunch of comments giving an overview of the library). References to 'Goldberg's Book' are to David E Goldberg's book, and references to 'Numerical Recipes' are to the Numerical Recipes in C book. "Genetic Algorithms in Search, Optimization, and Machine Learning" Goldberg, David Edward, 1953- Addison-Wesley Pub. Co., (c) 1989 ISBN 0-201-15767-5 "Numerical Recipes in C: The Art of Scientific Computing" Cambridge University Press, (c) 1988-1992 ISBN 0-521-43108-5 ------------------------------------------------------------------------------- Overview of who does what in the GAlibrary -- see http://lancet.mit.edu/ga/ ------------------------------------------------------------------------------- Here are the library capabilities and which parts of the library are involved: Genetic Algorithm This object contains the operators and data needed to perform the optimization. There are a few basic GA implementations in the library, including the basic 'simple' genetic algorithm described by Goldberg, the 'steady-state' genetic algorithm, the 'incremental' genetic algorithm based on the Genitor model, and the 'parallel' genetic algorithm that uses multiple populations in parallel on a single CPU. The base GA object defines many of the parameters and statistics useful when running an experiment. It also defines the basic interface for most genetic algorithms. Genome The genome object contains the actual problem-specific data as well as the mapping from data-domain to problem-domain (by way of the objective functions All of the genomes are derived from a base genome class. The base genome class defines the interface used by genetic algorithms to modify the data. Any genome used in an experiment must be derived from the base genom class as well as a user-defined data type (or one of the sample types provided in GAlib). The library includes array, tree, list, and binary-string data types to use if you do not want to define your own. Population Each population contains a bunch of genomes. Populations know how to select genomes. They also have housekeeping routines such as replace, remove, and add. A population can be given some intelligence by using its evaluation member rather than evaluting each individual on its own. Selection Selection is implemented as a member function of the population object. Any GA simply calls the population's 'select' member to get the genome that it needs to work with. Crossover/Mating Crossover is implemented as a separate object. We have various crossover objects, each corresponding to a genome type. These could be templatized, but that wouldn't buy us much since the behaviour depends upon the data type anyway. Crossover is not a member function of the genomes. I fretted over how to do this properly and decided to keep crossover as an operator separate from the genomes. The other viable option was to make crossover a member function of the genomes, but then changing the crossover during the course of the evolution becomes more difficult. Also, it is easier to define asexual (or other non-standard mating schemes) with an operator that is not a member of the genome object. When you create a GA, you specify a genome (or population of genomes). The GA asks the genome how it mates, and the genome returns a pointer to its preferred crossover method. You can set the crossover explicitly on the GA if you prefer. Using this scheme we can assign default crossover operators so that you don't have to specify a crossover unless you want to. Each genome type must have a corresponding crossover operator defined that can operate on that data type. The genetic algorithms don't care about the specific crossover type - they call the mating methods based upon the high level interface definition. Mutation Mutation is defined at the genome level and is implemented as a member function of the base genome class. Each genome must define its own mutation method that will operate on its specific data type. Replacement strategies The replacement strategy defines how a child is inserted into a population. Replacement strategies include child-replaces-parent, child-replaces-worst, and child-replaces-random. These make sense only for GAs with overlapping populations. Convergence and completion The GA defines a 'done' member that calls a user-defineable completion function to determine whether or not the GA is finished. Built-in completion routines include population-converged, best-converged and number-of-generations. Fitness vs Objective Note the difference between fitness function and objective function. In this library, the objective function is user-defined and tells (on an arbitrary scale) how well a genome performs relative to other genomes. The fitness function, on the other hand, takes objective function scores and processes them to produce a number for each genome that represents its fitness for mating/selection. The selection strategies include roulette wheel, tournament, linear ranking, and stochastic sampling. See the selector headers for more details about each strategy and its implementation. Speciation is included as a type of selection. To use the speciating selector you must define a distance function. See the selector header for more details. Scaling methods are loosely coupled with the selection strategies. They include linear scaling, sigma truncation, and ranking. See the fitness headers for more details about how you can mix and match scaling methods with selection strategies. Elitism Elitism is optional. If you want the best of each generation to be carried over to the next generation, turn on the elitism. If not, turn it off. This only works with non-overlapping populations. Initialization Each genome has its own initialization operator. When a GA is initialized, it initializes its populations, which in turn tells each chromomosome to initialize itself. You can use the initialization method to bias an initial population. This can be done either at the population level by customizing the population's initialization operator or at the genome level by customizing the genome's initilizer. Default initializers are included for most genomes. See the documentation and genome headers for more details. ------------------------------------------------------------------------------- Basic usage You create a GA by first instantiating the non-default parts that you want to use. For example, if you want a binary string genome with uniform crossover and roulette wheel selection, you would define an objective function, instantiate a genome, instantiate a uniform crossover operator, then instantiate the GA. Since the roulette wheel selector is the default, you do not need to instantiate one to use that method. In every case you MUST define an objective function and you MUST instantiate one copy of the genome type you want to use. ---------------------------------------------------------------------------- */ #ifndef _ga_ga_h_ #define _ga_ga_h_ // Make sure that we get the configuration into each of the galib components // that will be used. #include // These are the headers for all of the genetic algorithm classes. #include #include #include #include #include // Here we include the headers for all of the various genome types. #include #include #include #include #ifndef GALIB_USE_NO_TEMPLATES #include #include #include #include #include // We do *not* include the headers for template specializations. This prevents // unnecessary instantiations of template objects which causes grief to some // compilers. //#include //#include #endif #endif galib247/ga/GA1DArrayGenome.C0100644003643600364360000010563510573535473014755 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- array1.C mbwall 25feb95 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved DESCRIPTION: Source file for the 1D array genome. ---------------------------------------------------------------------------- */ #ifndef _ga_array1_C_ #define _ga_array1_C_ #include #include #include #include #include #include template int GA1DArrayIsHole(const GA1DArrayGenome&, const GA1DArrayGenome&, int, int, int); /* ---------------------------------------------------------------------------- 1DArrayGenome ---------------------------------------------------------------------------- */ template const char * GA1DArrayGenome::className() const {return "GA1DArrayGenome";} template int GA1DArrayGenome::classID() const {return GAID::ArrayGenome;} // Set all the initial values to NULL or zero, then allocate the space we'll // need (using the resize method). We do NOT call the initialize method at // this point - initialization must be done explicitly by the user of the // genome (eg when the population is created or reset). If we called the // initializer routine here then we could end up with multiple initializations // and/or calls to dummy initializers (for example when the genome is // created with a dummy initializer and the initializer is assigned later on). // Besides, we default to the no-initialization initializer by calling the // default genome constructor. template GA1DArrayGenome:: GA1DArrayGenome(unsigned int length, GAGenome::Evaluator f, void * u) : GAArray(length), GAGenome(DEFAULT_1DARRAY_INITIALIZER, DEFAULT_1DARRAY_MUTATOR, DEFAULT_1DARRAY_COMPARATOR) { evaluator(f); userData(u); nx=minX=maxX=length; crossover(DEFAULT_1DARRAY_CROSSOVER); } // This is the copy initializer. We set everything to the default values, then // copy the original. The Array creator takes care of zeroing the data. template GA1DArrayGenome:: GA1DArrayGenome(const GA1DArrayGenome & orig) : GAArray(orig.sz), GAGenome() { GA1DArrayGenome::copy(orig); } // Delete whatever we own. template GA1DArrayGenome::~GA1DArrayGenome() { } // This is the class-specific copy method. It will get called by the super // class since the superclass operator= is set up to call ccopy (and that is // what we define here - a virtual function). We should check to be sure that // both genomes are the same class and same dimension. This function tries // to be smart about they way it copies. If we already have data, then we do // a memcpy of the one we're supposed to copy. If we don't or we're not the // same size as the one we're supposed to copy, then we adjust ourselves. // The Array takes care of the resize in its copy method. template void GA1DArrayGenome::copy(const GAGenome & orig){ if(&orig == this) return; const GA1DArrayGenome* c = DYN_CAST(const GA1DArrayGenome*, &orig); if(c) { GAGenome::copy(*c); GAArray::copy(*c); nx = c->nx; minX = c->minX; maxX = c->maxX; } } template GAGenome * GA1DArrayGenome::clone(GAGenome::CloneMethod flag) const { GA1DArrayGenome *cpy = new GA1DArrayGenome(nx); if(flag == CONTENTS){ cpy->copy(*this); } else{ cpy->GAGenome::copy(*this); cpy->maxX = maxX; cpy->minX = minX; } return cpy; } // Resize the genome. // A negative value for the length means that we should randomly set the // length of the genome (if the resize behaviour is resizeable). If // someone tries to randomly set the length and the resize behaviour is fixed // length, then we don't do anything. // We pay attention to the values of minX and maxX - they determine what kind // of resizing we are allowed to do. If a resize is requested with a length // less than the min length specified by the behaviour, we set the minimum // to the length. If the length is longer than the max length specified by // the behaviour, we set the max value to the length. // We return the total size (in bits) of the genome after resize. // We don't do anything to the new contents! template int GA1DArrayGenome::resize(int len) { if(len == STA_CAST(int,nx)) return nx; if(len == GAGenome::ANY_SIZE) len = GARandomInt(minX, maxX); else if(len < 0) return nx; // do nothing else if(minX == maxX) minX=maxX=len; else{ if(len < STA_CAST(int,minX)) len=minX; if(len > STA_CAST(int,maxX)) len=maxX; } nx = GAArray::size(len); _evaluated = gaFalse; return this->sz; } #ifdef GALIB_USE_STREAMS // We don't define this one apriori. Do it in a specialization. template int GA1DArrayGenome::read(STD_ISTREAM &) { GAErr(GA_LOC, className(), "read", gaErrOpUndef); return 1; } // When we write the data to a stream we do it with spaces between elements. // Also, there is no newline at the end of the stream of digits. template int GA1DArrayGenome::write(STD_OSTREAM & os) const { for(unsigned int i=0; i int GA1DArrayGenome:: resizeBehaviour(unsigned int lower, unsigned int upper) { if(upper < lower){ GAErr(GA_LOC, className(), "resizeBehaviour", gaErrBadResizeBehaviour); return resizeBehaviour(); } minX = lower; maxX = upper; if(nx > upper) GA1DArrayGenome::resize(upper); if(nx < lower) GA1DArrayGenome::resize(lower); return resizeBehaviour(); } template int GA1DArrayGenome::resizeBehaviour() const { int val = maxX; if(maxX == minX) val = FIXED_SIZE; return val; } template int GA1DArrayGenome::equal(const GAGenome & c) const { const GA1DArrayGenome & b = DYN_CAST(const GA1DArrayGenome &, c); return((this == &c) ? 1 : ((nx != b.nx) ? 0 : GAArray::equal(b,0,0,nx))); } /* ---------------------------------------------------------------------------- 1DArrayAlleleGenome These genomes contain an allele set. When we create a new genome, it owns its own, independent allele set. If we clone a new genome, the new one gets a link to our allele set (so we don't end up with zillions of allele sets). Same is true for the copy constructor. The array may have a single allele set or an array of allele sets, depending on which creator was called. Either way, the allele set cannot be changed once the array is created. ---------------------------------------------------------------------------- */ template const char * GA1DArrayAlleleGenome::className() const {return "GA1DArrayAlleleGenome";} template int GA1DArrayAlleleGenome::classID() const {return GAID::ArrayAlleleGenome;} template GA1DArrayAlleleGenome:: GA1DArrayAlleleGenome(unsigned int length, const GAAlleleSet & s, GAGenome::Evaluator f, void * u) : GA1DArrayGenome(length, f, u){ naset = 1; aset = new GAAlleleSet[1]; aset[0] = s; initializer(GA1DArrayAlleleGenome::DEFAULT_1DARRAY_ALLELE_INITIALIZER); mutator(GA1DArrayAlleleGenome::DEFAULT_1DARRAY_ALLELE_MUTATOR); comparator(GA1DArrayAlleleGenome::DEFAULT_1DARRAY_ALLELE_COMPARATOR); crossover(GA1DArrayAlleleGenome::DEFAULT_1DARRAY_ALLELE_CROSSOVER); } template GA1DArrayAlleleGenome:: GA1DArrayAlleleGenome(const GAAlleleSetArray & sa, GAGenome::Evaluator f, void * u) : GA1DArrayGenome(sa.size(), f, u) { naset = sa.size(); aset = new GAAlleleSet[naset]; for(int i=0; i::DEFAULT_1DARRAY_ALLELE_INITIALIZER); mutator(GA1DArrayAlleleGenome::DEFAULT_1DARRAY_ALLELE_MUTATOR); comparator(GA1DArrayAlleleGenome::DEFAULT_1DARRAY_ALLELE_COMPARATOR); crossover(GA1DArrayAlleleGenome::DEFAULT_1DARRAY_ALLELE_CROSSOVER); } // The copy constructor creates a new genome whose allele set refers to the // original's allele set. template GA1DArrayAlleleGenome:: GA1DArrayAlleleGenome(const GA1DArrayAlleleGenome& orig) : GA1DArrayGenome(orig.sz) { naset = 0; aset = (GAAlleleSet*)0; GA1DArrayAlleleGenome::copy(orig); } // Delete the allele set template GA1DArrayAlleleGenome::~GA1DArrayAlleleGenome(){ delete [] aset; } // This implementation of clone does not make use of the contents/attributes // capability because this whole interface isn't quite right yet... Just // clone the entire thing, contents and all. template GAGenome * GA1DArrayAlleleGenome::clone(GAGenome::CloneMethod) const { return new GA1DArrayAlleleGenome(*this); } template void GA1DArrayAlleleGenome::copy(const GAGenome& orig){ if(&orig == this) return; const GA1DArrayAlleleGenome * c = DYN_CAST(const GA1DArrayAlleleGenome*, &orig); if(c) { GA1DArrayGenome::copy(*c); if(naset != c->naset){ delete [] aset; naset = c->naset; aset = new GAAlleleSet[naset]; } for(int i=0; iaset[i]); } } // If we resize to a larger length then we need to set the contents to a valid // value (ie one of our alleles). template int GA1DArrayAlleleGenome::resize(int len){ unsigned int oldx = this->nx; GA1DArrayGenome::resize(len); if(this->nx > oldx){ for(unsigned int i=oldx; inx; i++) this->a[i] = aset[i % naset].allele(); } return len; } // Define these so they can easily be specialized as needed. #ifdef GALIB_USE_STREAMS template int GA1DArrayAlleleGenome::read(STD_ISTREAM& is){ return GA1DArrayGenome::read(is); } template int GA1DArrayAlleleGenome::write(STD_OSTREAM& os) const { return GA1DArrayGenome::write(os); } #endif template int GA1DArrayAlleleGenome::equal(const GAGenome & c) const { return GA1DArrayGenome::equal(c); } /* ---------------------------------------------------------------------------- Operator definitions ---------------------------------------------------------------------------- */ // The random initializer sets the elements of the array based on the alleles // set. We choose randomly the allele for each element. template void GA1DArrayAlleleGenome::UniformInitializer(GAGenome & c) { GA1DArrayAlleleGenome &child= DYN_CAST(GA1DArrayAlleleGenome &, c); child.resize(GAGenome::ANY_SIZE); // let chrom resize if it can for(int i=child.length()-1; i>=0; i--) child.gene(i, child.alleleset(i).allele()); } // Random initializer for order-based genome. Loop through the genome // and assign each element the next allele in the allele set. Once each // element has been initialized, scramble the contents by swapping elements. // This assumes that there is only one allele set for the array. template void GA1DArrayAlleleGenome::OrderedInitializer(GAGenome & c) { GA1DArrayAlleleGenome &child= DYN_CAST(GA1DArrayAlleleGenome &, c); child.resize(GAGenome::ANY_SIZE); // let chrom resize if it can int length = child.length()-1; int n=0; int i; for(i=length; i>=0; i--){ child.gene(i, child.alleleset().allele(n++)); if(n >= child.alleleset().size()) n = 0; } for(i=length; i>=0; i--) child.swap(i, GARandomInt(0, length)); } // Randomly pick elements in the array then set the element to any of the // alleles in the allele set for this genome. This will work for any number // of allele sets for a given array. template int GA1DArrayAlleleGenome::FlipMutator(GAGenome & c, float pmut) { GA1DArrayAlleleGenome &child= DYN_CAST(GA1DArrayAlleleGenome &, c); register int n, i; if(pmut <= 0.0) return(0); float nMut = pmut * STA_CAST(float,child.length()); if(nMut < 1.0){ // we have to do a flip test on each bit nMut = 0; for(i=child.length()-1; i>=0; i--){ if(GAFlipCoin(pmut)){ child.gene(i, child.alleleset(i).allele()); nMut++; } } } else{ // only flip the number of bits we need to flip for(n=0; n int GA1DArrayGenome::SwapMutator(GAGenome & c, float pmut) { GA1DArrayGenome &child=DYN_CAST(GA1DArrayGenome&, c); register int n, i; if(pmut <= 0.0) return(0); float nMut = pmut * STA_CAST(float,child.length()); int length = child.length()-1; if(nMut < 1.0){ // we have to do a flip test on each bit nMut = 0; for(i=length; i>=0; i--){ if(GAFlipCoin(pmut)){ child.swap(i, GARandomInt(0, length)); nMut++; } } } else{ // only flip the number of bits we need to flip for(n=0; n float GA1DArrayGenome:: ElementComparator(const GAGenome& a, const GAGenome& b) { const GA1DArrayGenome& sis= DYN_CAST(const GA1DArrayGenome&, a); const GA1DArrayGenome& bro= DYN_CAST(const GA1DArrayGenome&, b); if(sis.length() != bro.length()) return -1; if(sis.length() == 0) return 0; float count = 0.0; for(int i=sis.length()-1; i>=0; i--) count += ((sis.gene(i) == bro.gene(i)) ? 0 : 1); return count/sis.length(); } #define SWAP(a,b) {unsigned int tmp=a; a=b; b=tmp;} // Randomly take bits from each parent. For each bit we flip a coin to see if // that bit should come from the mother or the father. If strings are // different lengths then we need to use the mask to get things right. template int GA1DArrayGenome:: UniformCrossover(const GAGenome& p1, const GAGenome& p2, GAGenome* c1, GAGenome* c2){ const GA1DArrayGenome &mom=DYN_CAST(const GA1DArrayGenome &, p1); const GA1DArrayGenome &dad=DYN_CAST(const GA1DArrayGenome &, p2); int n=0; int i; if(c1 && c2){ GA1DArrayGenome &sis=DYN_CAST(GA1DArrayGenome &, *c1); GA1DArrayGenome &bro=DYN_CAST(GA1DArrayGenome &, *c2); if(sis.length() == bro.length() && mom.length() == dad.length() && sis.length() == mom.length()){ for(i=sis.length()-1; i>=0; i--){ if(GARandomBit()){ sis.gene(i, mom.gene(i)); bro.gene(i, dad.gene(i)); } else{ sis.gene(i, dad.gene(i)); bro.gene(i, mom.gene(i)); } } } else{ GAMask mask; int start; int max = (sis.length() > bro.length()) ? sis.length() : bro.length(); int min = (mom.length() < dad.length()) ? mom.length() : dad.length(); mask.size(max); for(i=0; i=0; i--) sis.gene(i, (mask[i] ? mom.gene(i) : dad.gene(i))); start = (bro.length() < min) ? bro.length()-1 : min-1; for(i=start; i>=0; i--) bro.gene(i, (mask[i] ? dad.gene(i) : mom.gene(i))); } n = 2; } else if(c1 || c2){ GA1DArrayGenome &sis = (c1 ? DYN_CAST(GA1DArrayGenome &, *c1) : DYN_CAST(GA1DArrayGenome &, *c2)); if(mom.length() == dad.length() && sis.length() == mom.length()){ for(i=sis.length()-1; i>=0; i--) sis.gene(i, (GARandomBit() ? mom.gene(i) : dad.gene(i))); } else{ int min = (mom.length() < dad.length()) ? mom.length() : dad.length(); min = (sis.length() < min) ? sis.length() : min; for(i=min-1; i>=0; i--) sis.gene(i, (GARandomBit() ? mom.gene(i) : dad.gene(i))); } n = 1; } return n; } // Single point crossover for 1D array genomes. Pick a single point then // copy genetic material from each parent. We must allow for resizable genomes // so be sure to check the behaviours before we do the crossovers. If resizing // is allowed then the children will change depending on where the site is // located. It is also possible to have a mixture of resize behaviours, but // we won't worry about that at this point. If this happens we just say that // we cannot handle that and post an error message. template int GA1DArrayGenome:: OnePointCrossover(const GAGenome& p1, const GAGenome& p2, GAGenome* c1, GAGenome* c2){ const GA1DArrayGenome &mom=DYN_CAST(const GA1DArrayGenome &, p1); const GA1DArrayGenome &dad=DYN_CAST(const GA1DArrayGenome &, p2); int nc=0; unsigned int momsite, momlen; unsigned int dadsite, dadlen; if(c1 && c2){ GA1DArrayGenome &sis=DYN_CAST(GA1DArrayGenome &, *c1); GA1DArrayGenome &bro=DYN_CAST(GA1DArrayGenome &, *c2); if(sis.resizeBehaviour() == GAGenome::FIXED_SIZE && bro.resizeBehaviour() == GAGenome::FIXED_SIZE){ if(mom.length() != dad.length() || sis.length() != bro.length() || sis.length() != mom.length()){ GAErr(GA_LOC, mom.className(), "one-point cross", gaErrSameLengthReqd); return nc; } momsite = dadsite = GARandomInt(0, mom.length()); momlen = dadlen = mom.length() - momsite; } else if(sis.resizeBehaviour() == GAGenome::FIXED_SIZE || bro.resizeBehaviour() == GAGenome::FIXED_SIZE){ GAErr(GA_LOC, mom.className(), "one-point cross", gaErrSameBehavReqd); return nc; } else{ momsite = GARandomInt(0, mom.length()); dadsite = GARandomInt(0, dad.length()); momlen = mom.length() - momsite; dadlen = dad.length() - dadsite; sis.resize(momsite+dadlen); bro.resize(dadsite+momlen); } sis.copy(mom, 0, 0, momsite); sis.copy(dad, momsite, dadsite, dadlen); bro.copy(dad, 0, 0, dadsite); bro.copy(mom, dadsite, momsite, momlen); nc = 2; } else if(c1 || c2){ GA1DArrayGenome &sis = (c1 ? DYN_CAST(GA1DArrayGenome &, *c1) : DYN_CAST(GA1DArrayGenome &, *c2)); if(sis.resizeBehaviour() == GAGenome::FIXED_SIZE){ if(mom.length() != dad.length() || sis.length() != mom.length()){ GAErr(GA_LOC, mom.className(), "one-point cross", gaErrSameLengthReqd); return nc; } momsite = dadsite = GARandomInt(0, mom.length()); momlen = dadlen = mom.length() - momsite; } else{ momsite = GARandomInt(0, mom.length()); dadsite = GARandomInt(0, dad.length()); momlen = mom.length() - momsite; dadlen = dad.length() - dadsite; sis.resize(momsite+dadlen); } if(GARandomBit()){ sis.copy(mom, 0, 0, momsite); sis.copy(dad, momsite, dadsite, dadlen); } else{ sis.copy(dad, 0, 0, dadsite); sis.copy(mom, dadsite, momsite, momlen); } nc = 1; } return nc; } // Two point crossover for the 1D array genome. Similar to the single point // crossover, but here we pick two points then grab the sections based upon // those two points. // When we pick the points, it doesn't matter where they fall (one is not // dependent upon the other). Make sure we get the lesser one into the first // position of our site array. template int GA1DArrayGenome:: TwoPointCrossover(const GAGenome& p1, const GAGenome& p2, GAGenome* c1, GAGenome* c2){ const GA1DArrayGenome &mom=DYN_CAST(const GA1DArrayGenome &, p1); const GA1DArrayGenome &dad=DYN_CAST(const GA1DArrayGenome &, p2); int nc=0; unsigned int momsite[2], momlen[2]; unsigned int dadsite[2], dadlen[2]; if(c1 && c2){ GA1DArrayGenome &sis=DYN_CAST(GA1DArrayGenome &, *c1); GA1DArrayGenome &bro=DYN_CAST(GA1DArrayGenome &, *c2); if(sis.resizeBehaviour() == GAGenome::FIXED_SIZE && bro.resizeBehaviour() == GAGenome::FIXED_SIZE){ if(mom.length() != dad.length() || sis.length() != bro.length() || sis.length() != mom.length()){ GAErr(GA_LOC, mom.className(), "two-point cross", gaErrSameLengthReqd); return nc; } momsite[0] = GARandomInt(0, mom.length()); momsite[1] = GARandomInt(0, mom.length()); if(momsite[0] > momsite[1]) SWAP(momsite[0], momsite[1]); momlen[0] = momsite[1] - momsite[0]; momlen[1] = mom.length() - momsite[1]; dadsite[0] = momsite[0]; dadsite[1] = momsite[1]; dadlen[0] = momlen[0]; dadlen[1] = momlen[1]; } else if(sis.resizeBehaviour() == GAGenome::FIXED_SIZE || bro.resizeBehaviour() == GAGenome::FIXED_SIZE){ return nc; } else{ momsite[0] = GARandomInt(0, mom.length()); momsite[1] = GARandomInt(0, mom.length()); if(momsite[0] > momsite[1]) SWAP(momsite[0], momsite[1]); momlen[0] = momsite[1] - momsite[0]; momlen[1] = mom.length() - momsite[1]; dadsite[0] = GARandomInt(0, dad.length()); dadsite[1] = GARandomInt(0, dad.length()); if(dadsite[0] > dadsite[1]) SWAP(dadsite[0], dadsite[1]); dadlen[0] = dadsite[1] - dadsite[0]; dadlen[1] = dad.length() - dadsite[1]; sis.resize(momsite[0]+dadlen[0]+momlen[1]); bro.resize(dadsite[0]+momlen[0]+dadlen[1]); } sis.copy(mom, 0, 0, momsite[0]); sis.copy(dad, momsite[0], dadsite[0], dadlen[0]); sis.copy(mom, momsite[0]+dadlen[0], momsite[1], momlen[1]); bro.copy(dad, 0, 0, dadsite[0]); bro.copy(mom, dadsite[0], momsite[0], momlen[0]); bro.copy(dad, dadsite[0]+momlen[0], dadsite[1], dadlen[1]); nc = 2; } else if(c1 || c2){ GA1DArrayGenome &sis = (c1 ? DYN_CAST(GA1DArrayGenome &, *c1) : DYN_CAST(GA1DArrayGenome &, *c2)); if(sis.resizeBehaviour() == GAGenome::FIXED_SIZE){ if(mom.length() != dad.length() || sis.length() != mom.length()){ GAErr(GA_LOC, mom.className(), "two-point cross", gaErrSameLengthReqd); return nc; } momsite[0] = GARandomInt(0, mom.length()); momsite[1] = GARandomInt(0, mom.length()); if(momsite[0] > momsite[1]) SWAP(momsite[0], momsite[1]); momlen[0] = momsite[1] - momsite[0]; momlen[1] = mom.length() - momsite[1]; dadsite[0] = momsite[0]; dadsite[1] = momsite[1]; dadlen[0] = momlen[0]; dadlen[1] = momlen[1]; } else{ momsite[0] = GARandomInt(0, mom.length()); momsite[1] = GARandomInt(0, mom.length()); if(momsite[0] > momsite[1]) SWAP(momsite[0], momsite[1]); momlen[0] = momsite[1] - momsite[0]; momlen[1] = mom.length() - momsite[1]; dadsite[0] = GARandomInt(0, dad.length()); dadsite[1] = GARandomInt(0, dad.length()); if(dadsite[0] > dadsite[1]) SWAP(dadsite[0], dadsite[1]); dadlen[0] = dadsite[1] - dadsite[0]; dadlen[1] = dad.length() - dadsite[1]; sis.resize(momsite[0]+dadlen[0]+momlen[1]); } if(GARandomBit()){ sis.copy(mom, 0, 0, momsite[0]); sis.copy(dad, momsite[0], dadsite[0], dadlen[0]); sis.copy(mom, momsite[0]+dadlen[0], momsite[1], momlen[1]); } else{ sis.copy(dad, 0, 0, dadsite[0]); sis.copy(mom, dadsite[0], momsite[0], momlen[0]); sis.copy(dad, dadsite[0]+momlen[0], dadsite[1], dadlen[1]); } nc = 1; } return nc; } // Even and odd crossover for the array works just like it does for the // binary strings. For even crossover we take the 0th element and every other // one after that from the mother. The 1st and every other come from the // father. For odd crossover, we do just the opposite. template int GA1DArrayGenome:: EvenOddCrossover(const GAGenome& p1, const GAGenome& p2, GAGenome* c1, GAGenome* c2){ const GA1DArrayGenome &mom=DYN_CAST(const GA1DArrayGenome &, p1); const GA1DArrayGenome &dad=DYN_CAST(const GA1DArrayGenome &, p2); int nc=0; int i; if(c1 && c2){ GA1DArrayGenome &sis=DYN_CAST(GA1DArrayGenome &, *c1); GA1DArrayGenome &bro=DYN_CAST(GA1DArrayGenome &, *c2); if(sis.length() == bro.length() && mom.length() == dad.length() && sis.length() == mom.length()){ for(i=sis.length()-1; i>=1; i-=2){ sis.gene(i, mom.gene(i)); bro.gene(i, dad.gene(i)); sis.gene(i-1, dad.gene(i-1)); bro.gene(i-1, mom.gene(i-1)); } if(i==0){ sis.gene(0, mom.gene(0)); bro.gene(0, dad.gene(0)); } } else{ int start; int min = (mom.length() < dad.length()) ? mom.length() : dad.length(); start = (sis.length() < min) ? sis.length()-1 : min-1; for(i=start; i>=0; i--) sis.gene(i, ((i%2 == 0) ? mom.gene(i) : dad.gene(i))); start = (bro.length() < min) ? bro.length()-1 : min-1; for(i=start; i>=0; i--) bro.gene(i, ((i%2 == 0) ? dad.gene(i) : mom.gene(i))); } nc = 2; } else if(c1 || c2){ GA1DArrayGenome &sis = (c1 ? DYN_CAST(GA1DArrayGenome &, *c1) : DYN_CAST(GA1DArrayGenome &, *c2)); if(mom.length() == dad.length() && sis.length() == mom.length()){ for(i=sis.length()-1; i>=1; i-=2){ sis.gene(i, mom.gene(i)); sis.gene(i-1, dad.gene(i-1)); } if(i==0){ sis.gene(0, mom.gene(0)); } } else{ int min = (mom.length() < dad.length()) ? mom.length() : dad.length(); min = (sis.length() < min) ? sis.length()-1 : min-1; for(i=min; i>=0; i--) sis.gene(i, ((i%2 == 0) ? mom.gene(i) : dad.gene(i))); } nc = 1; } return nc; } // Partial match crossover for the 1D array genome. This uses the partial // matching algorithm described in Goldberg's book. // Parents and children must be the same size for this crossover to work. If // they are not, we post an error message. // We make sure that b will be greater than a. template int GA1DArrayGenome:: PartialMatchCrossover(const GAGenome& p1, const GAGenome& p2, GAGenome* c1, GAGenome* c2){ const GA1DArrayGenome &mom=DYN_CAST(const GA1DArrayGenome &, p1); const GA1DArrayGenome &dad=DYN_CAST(const GA1DArrayGenome &, p2); int nc=0; int a = GARandomInt(0, mom.length()); int b = GARandomInt(0, dad.length()); if(b < a) SWAP(a,b); int i,j,index; if(mom.length() != dad.length()){ GAErr(GA_LOC, mom.className(), "parial match cross", gaErrBadParentLength); return nc; } if(c1 && c2){ GA1DArrayGenome &sis=DYN_CAST(GA1DArrayGenome &, *c1); GA1DArrayGenome &bro=DYN_CAST(GA1DArrayGenome &, *c2); sis.GAArray::copy(mom); for(i=a, index=a; i::copy(dad); for(i=a, index=a; i &sis = (c1 ? DYN_CAST(GA1DArrayGenome &, *c1) : DYN_CAST(GA1DArrayGenome &, *c2)); const GA1DArrayGenome *parent1, *parent2; if(GARandomBit()) { parent1 = &mom; parent2 = &dad; } else { parent1 = &dad; parent2 = &mom; } sis.GAArray::copy(*parent1); for(i=a, index=a; igene(index); j++); sis.swap(i,j); } nc = 1; } return nc; } // This function determines whether or not an indexed position is a hole that // we can substitute into. It does a linear search to find the holes (yuk). template int GA1DArrayIsHole(const GA1DArrayGenome &c, const GA1DArrayGenome &dad, int index, int a, int b){ for(int i=a; i int GA1DArrayGenome:: OrderCrossover(const GAGenome& p1, const GAGenome& p2, GAGenome* c1, GAGenome* c2){ const GA1DArrayGenome &mom=DYN_CAST(const GA1DArrayGenome &, p1); const GA1DArrayGenome &dad=DYN_CAST(const GA1DArrayGenome &, p2); int nc=0; int a = GARandomInt(0, mom.length()); int b = GARandomInt(0, mom.length()); if(b < a) SWAP(a,b); int i,j, index; if(mom.length() != dad.length()){ GAErr(GA_LOC, mom.className(), "order cross", gaErrBadParentLength); return nc; } if(c1 && c2){ GA1DArrayGenome &sis=DYN_CAST(GA1DArrayGenome &, *c1); GA1DArrayGenome &bro=DYN_CAST(GA1DArrayGenome &, *c2); // Copy the parent sis.GAArray::copy(mom); // Move all the 'holes' into the crossover section for(i=0, index=b; i= sis.size()) index=0; if(GA1DArrayIsHole(sis,dad,index,a,b)) break; } for(; i= sis.size()) index=0; j=index; do{ j++; if(j >= sis.size()) j=0; } while(GA1DArrayIsHole(sis,dad,j,a,b)); sis.swap(index,j); } // Now put the 'holes' in the proper order within the crossover section. for(i=a; i::copy(dad); // Move all the 'holes' into the crossover section for(i=0, index=b; i= bro.size()) index=0; if(GA1DArrayIsHole(bro,mom,index,a,b)) break; } for(; i= bro.size()) index=0; j=index; do{ j++; if(j >= bro.size()) j=0; } while(GA1DArrayIsHole(bro,mom,j,a,b)); bro.swap(index,j); } // Now put the 'holes' in the proper order within the crossover section. for(i=a; i &sis = (c1 ? DYN_CAST(GA1DArrayGenome &, *c1) : DYN_CAST(GA1DArrayGenome &, *c2)); const GA1DArrayGenome *parent1, *parent2; if(GARandomBit()) { parent1 = &mom; parent2 = &dad; } else { parent1 = &dad; parent2 = &mom; } sis.GAArray::copy(*parent1); for(i=0, index=b; i= sis.size()) index=0; if(GA1DArrayIsHole(sis,*parent2,index,a,b)) break; } for(; i= sis.size()) index=0; j=index; do{ j++; if(j >= sis.size()) j=0; } while(GA1DArrayIsHole(sis,*parent2,j,a,b)); sis.swap(index,j); } for(i=a; igene(i)){ for(j=i+1; jgene(i)) sis.swap(i,j); } } nc = 1; } return nc; } // Cycle crossover for the 1D array genome. This is implemented as described // in goldberg's book. The first is picked from mom, then cycle using dad. // Finally, fill in the gaps with the elements from dad. // We allocate space for a temporary array in this routine. It never frees // the memory that it uses, so you might want to re-think this if you're really // memory-constrained (similar to what we do with the uniform crossover when // the children are resizeable). // Allocate space for an array of flags. We use this to keep track of whether // the child's contents came from the mother or the father. We don't free the // space here, but it is not a memory leak. // The first step is to cycle through mom & dad to get the cyclic part of // the crossover. Then fill in the rest of the sis with dad's contents that // we didn't use in the cycle. Finally, do the same thing for the other child. // Notice that this implementation makes serious use of the operator= for the // objects in the array. It also requires the operator != and == comparators. template int GA1DArrayGenome:: CycleCrossover(const GAGenome& p1, const GAGenome& p2, GAGenome* c1, GAGenome* c2){ const GA1DArrayGenome &mom=DYN_CAST(const GA1DArrayGenome &, p1); const GA1DArrayGenome &dad=DYN_CAST(const GA1DArrayGenome &, p2); int nc=0; int i, current=0; if(mom.length() != dad.length()){ GAErr(GA_LOC, mom.className(), "cycle cross", gaErrBadParentLength); return nc; } if(c1 && c2){ GAMask mask; GA1DArrayGenome &sis=DYN_CAST(GA1DArrayGenome &, *c1); GA1DArrayGenome &bro=DYN_CAST(GA1DArrayGenome &, *c2); mask.size(sis.length()); mask.clear(); sis.gene(0, mom.gene(0)); mask[0] = 1; while(dad.gene(current) != mom.gene(0)){ for(i=0; i &sis = (c1 ? DYN_CAST(GA1DArrayGenome &, *c1) : DYN_CAST(GA1DArrayGenome &, *c2)); const GA1DArrayGenome *parent1, *parent2; if(GARandomBit()) { parent1 = &mom; parent2 = &dad; } else { parent1 = &dad; parent2 = &mom; } GAMask mask; mask.size(sis.length()); mask.clear(); sis.gene(0, parent1->gene(0)); mask[0] = 1; while(parent2->gene(current) != parent1->gene(0)){ for(i=0; igene(i) == parent2->gene(current)){ sis.gene(i, parent1->gene(i)); mask[i] = 1; current = i; break; } } } for(i=0; igene(i)); nc = 1; } return nc; } #undef SWAP #endif galib247/ga/GA1DArrayGenome.h0100644003643600364360000001520010573535474015007 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- array1.h mbwall 25feb95 Copyright (c) 1995-1996 Massachusetts Institute of Technology all rights reserved DESCRIPTION: This header defines the interface for the 1D array genome. You can use ANY kind of object in this genome. But notice that it is really easy to optimize this for some of the simpler types. I'll try to do that for common instantiations (float, char). The objects in the array must have the following operators defined: = == != >> must be defined if you use the default read methods TO DO: *** If you want speed, specialize the comparison routines and copy routines so that you can use memcpy, memmove, memcmp rather than looping through each element. *** make the object defined for simple types, if you want to use complex types then specialize to do member copy rather than bit copy (that way simple users won't sacrifice speed, and complex users will get more complexity) ---------------------------------------------------------------------------- */ #ifndef _ga_array1_h_ #define _ga_array1_h_ #include #include #include /* ---------------------------------------------------------------------------- 1DArrayGenome ---------------------------------------------------------------------------- */ template class GA1DArrayGenome : public GAArray, public GAGenome { public: GADeclareIdentity(); static int SwapMutator(GAGenome&, float); static float ElementComparator(const GAGenome&, const GAGenome&); static int UniformCrossover(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*); static int EvenOddCrossover(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*); static int OnePointCrossover(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*); static int TwoPointCrossover(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*); static int PartialMatchCrossover(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*); static int OrderCrossover(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*); static int CycleCrossover(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*); public: GA1DArrayGenome(unsigned int x, GAGenome::Evaluator f=(GAGenome::Evaluator)0, void * u=(void *)0); GA1DArrayGenome(const GA1DArrayGenome & orig); GA1DArrayGenome& operator=(const GAGenome& orig) {copy(orig); return *this;} GA1DArrayGenome& operator=(const T array []) // no err checks! {for(unsigned int i=0; isz; i++) gene(i, *(array+i)); return *this;} virtual ~GA1DArrayGenome(); virtual GAGenome *clone(GAGenome::CloneMethod flag=CONTENTS) const; virtual void copy(const GAGenome &); #ifdef GALIB_USE_STREAMS virtual int read(STD_ISTREAM & is); virtual int write (STD_OSTREAM & os) const; #endif virtual int equal(const GAGenome & c) const ; const T & gene(unsigned int x=0) const {return this->a[x];} T & gene(unsigned int x, const T & value){ if(this->a[x] != value){ this->a[x] = value; _evaluated = gaFalse;} return this->a[x]; } int length() const {return nx;} int length(int x){resize(x); return nx;} virtual int resize(int x); int resizeBehaviour() const ; int resizeBehaviour(unsigned int lx, unsigned int ux); void copy(const GA1DArrayGenome & orig, unsigned int r, unsigned int x, unsigned int l){ if(l > 0 && x < orig.nx && r < nx){ if(x + l > orig.nx) l = orig.nx - x; if(r + l > nx) l = nx - r; GAArray::copy(orig,r,x,l); } _evaluated = gaFalse; } void swap(unsigned int i, unsigned int j) {GAArray::swap(i,j); _evaluated = gaFalse; } protected: unsigned int nx; // how long is the data string? unsigned int minX; // what is the lower limit? unsigned int maxX; // what is the upper limit? private: GA1DArrayGenome() : GAArray(0){} }; /* ---------------------------------------------------------------------------- 1DArrayAlleleGenome ------------------------------------------------------------------------------- We don't do any error checking on the assignment to const array of type T, so the array may contain elements that are not in the allele set. When we clone, we link the new allele set to our own so that we don't make unnecessary copies. If someone sets a new allele set on the genome, then we make a complete new copy of the new one and break any link to a previous one. It is OK to resize these genomes, so we don't have to protect the resize. If this is an order-based genome then resizing should be done when the allele set is changed, but there is nothing implicit in the object that tells us that this is an order-based genome, so that's up to the user to take care of. If you're really concerned about catching this type of error, derive a class from this class that does order-based protection. I have defined all of the genome virtual functions here to make it easier to do specializations (you can specialize this class instead if its superclass). We define our own resize so that we can set to allele values on resize to a bigger length. ---------------------------------------------------------------------------- */ template class GA1DArrayAlleleGenome : public GA1DArrayGenome { public: GADeclareIdentity(); static void UniformInitializer(GAGenome&); static void OrderedInitializer(GAGenome&); static int FlipMutator(GAGenome&, float); public: GA1DArrayAlleleGenome(unsigned int x, const GAAlleleSet & a, GAGenome::Evaluator f=(GAGenome::Evaluator)0, void * u=(void *)0); GA1DArrayAlleleGenome(const GAAlleleSetArray & a, GAGenome::Evaluator f=(GAGenome::Evaluator)0, void * u=(void *)0); GA1DArrayAlleleGenome(const GA1DArrayAlleleGenome&); GA1DArrayAlleleGenome& operator=(const GAGenome& arr) {copy(arr); return *this;} GA1DArrayAlleleGenome& operator=(const T array []) // no err checks! {GA1DArrayGenome::operator=(array); return *this;} virtual ~GA1DArrayAlleleGenome(); virtual GAGenome *clone(GAGenome::CloneMethod flag=GAGenome::CONTENTS) const; virtual void copy(const GAGenome &); #ifdef GALIB_USE_STREAMS virtual int read(STD_ISTREAM & is); virtual int write (STD_OSTREAM & os) const; #endif virtual int equal(const GAGenome & c) const ; virtual int resize(int x); const GAAlleleSet& alleleset(unsigned int i=0) const {return aset[i%naset];} protected: int naset; GAAlleleSet * aset; // the allele set(s) for this genome }; #ifdef GALIB_USE_BORLAND_INST #include #endif #endif galib247/ga/GA1DBinStrGenome.C0100644003643600364360000005414410573535473015076 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- binstr1.C mbwall 19apr95 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved DESCRIPTION: Source file for the 1D binary string genome. ---------------------------------------------------------------------------- */ #include #include #include #include #include #include #include #include #define SWAP(a,b) {unsigned int tmp=a; a=b; b=tmp;} /* ---------------------------------------------------------------------------- Genome class definition ---------------------------------------------------------------------------- */ // Set all the initial values to NULL or zero, then allocate the space we'll // need (using the resize method). We do NOT call the initialize method at // this point - initialization must be done explicitly by the user of the // genome (eg when the population is created or reset). If we called the // initializer routine here then we could end up with multiple initializations // and/or calls to dummy initializers (for example when the genome is // created with a dummy initializer and the initializer is assigned later on). GA1DBinaryStringGenome:: GA1DBinaryStringGenome(unsigned int len, GAGenome::Evaluator f, void * u) : GABinaryString(len), GAGenome(DEFAULT_1DBINSTR_INITIALIZER, DEFAULT_1DBINSTR_MUTATOR, DEFAULT_1DBINSTR_COMPARATOR) { evaluator(f); userData(u); crossover(DEFAULT_1DBINSTR_CROSSOVER); // assign the default sexual crossover nx=minX=maxX=0; resize(len); } // This is the copy initializer. We set everything to the default values, then // copy the original. The BinaryStringGenome creator takes care of zeroing // the data and sz members. GA1DBinaryStringGenome:: GA1DBinaryStringGenome(const GA1DBinaryStringGenome& orig) : GABinaryString(orig.GABinaryString::size()), GAGenome() { nx=minX=maxX=0; GA1DBinaryStringGenome::copy(orig); } GA1DBinaryStringGenome::~GA1DBinaryStringGenome() { } // The clone member creates a duplicate (exact or just attributes, depending // on the flag). The caller is responsible for freeing the memory that is // allocated by this method. GAGenome* GA1DBinaryStringGenome::clone(GAGenome::CloneMethod flag) const { GA1DBinaryStringGenome *cpy = new GA1DBinaryStringGenome(nx); if(flag == CONTENTS){ cpy->copy(*this); } else{ cpy->GAGenome::copy(*this); cpy->maxX = maxX; cpy->minX = minX; } return cpy; } // This is the class-specific copy method. It will get called by the super // class since the superclass operator= is set up to call ccopy (and that is // what we define here - a virtual function). We should check to be sure that // both genomes are the same class and same dimension. This function tries // to be smart about they way it copies. If we already have data, then we do // a memcpy of the one we're supposed to copy. If we don't or we're not the // same size as the one we're supposed to copy, then we adjust ourselves. // The BinaryStringGenome takes care of the resize in its copy method. // It also copies the bitstring for us. void GA1DBinaryStringGenome::copy(const GAGenome & orig) { if(&orig == this) return; const GA1DBinaryStringGenome* c = DYN_CAST(const GA1DBinaryStringGenome*, &orig); if(c) { GAGenome::copy(*c); GABinaryString::copy(*c); nx = c->nx; minX = c->minX; maxX = c->maxX; } } // Resize the genome. If someone specifies ANY_RESIZE then we pick a random // size within the behaviour limits that have been set. If limits have been // set and someone passes us something outside the limits, we resize to the // closest bound. If the genome is fixed size (ie min limit equals max limit) // then we resize to the specified value and move the min/max to match it. int GA1DBinaryStringGenome::resize(int l) { if(l == STA_CAST(int, nx)) return nx; if(l == GAGenome::ANY_SIZE) l = GARandomInt(minX, maxX); else if(l < 0) return nx; // do nothing else if(minX == maxX) minX=maxX=l; else{ if(l < STA_CAST(int, minX)) l=minX; if(l > STA_CAST(int, maxX)) l=maxX; } GABinaryString::resize(l); if(l > STA_CAST(int, nx)) for(int i=nx; i> c; if(isdigit(c)) gene(i++, ((c == '0') ? 0 : 1)); } _evaluated = gaFalse; if(is.eof() && i < nx){ GAErr(GA_LOC, className(), "read", gaErrUnexpectedEOF); is.clear(STD_IOS_BADBIT | is.rdstate()); return 1; } return 0; } // When we write the data to a stream we do it without any spaces. Also, there // is no newline at the end of the stream of digits. int GA1DBinaryStringGenome::write(STD_OSTREAM & os) const { for(unsigned int i=0; i upper) resize(upper); if(nx < lower) resize(lower); return resizeBehaviour(); } int GA1DBinaryStringGenome::resizeBehaviour() const { int val = maxX; if(maxX == minX) val = FIXED_SIZE; return val; } int GA1DBinaryStringGenome:: equal(const GA1DBinaryStringGenome& c, unsigned int dest, unsigned int src, unsigned int len) const { return GABinaryString::equal(c,dest,src,len); } int GA1DBinaryStringGenome::equal(const GAGenome & c) const { if(this == &c) return 1; const GA1DBinaryStringGenome* b = DYN_CAST(const GA1DBinaryStringGenome*,&c); int eq = 0; if(b) { eq = ((nx != b->nx) ? 0 : GABinaryString::equal(*b,0,0,nx)); } return eq; } /* ---------------------------------------------------------------------------- Operators ---------------------------------------------------------------------------- */ // Set the bits of the genome to random values. We use the library's // random bit function so we don't have to worry about machine-specific stuff. // We also do a resize so the genome can resize itself (randomly) if it // is a resizeable genome. void GA1DBinaryStringGenome::UniformInitializer(GAGenome & c) { GA1DBinaryStringGenome &child=DYN_CAST(GA1DBinaryStringGenome &, c); child.resize(GAGenome::ANY_SIZE); // let chrom resize if it can for(int i=child.length()-1; i>=0; i--) child.gene(i, GARandomBit()); // initial values are all random } // Unset all of the bits in the genome. void GA1DBinaryStringGenome::UnsetInitializer(GAGenome & c) { GA1DBinaryStringGenome &child=DYN_CAST(GA1DBinaryStringGenome &, c); child.resize(GAGenome::ANY_SIZE); // let chrom resize if it can child.unset(0, child.length()); } // Set all of the bits in the genome. void GA1DBinaryStringGenome::SetInitializer(GAGenome & c) { GA1DBinaryStringGenome &child=DYN_CAST(GA1DBinaryStringGenome &, c); child.resize(GAGenome::ANY_SIZE); // let chrom resize if it can child.set(0, child.length()); } // This function gets called a lot (especially for the simple ga) so it must // be as streamlined as possible. If the mutation probability is small, then // we must call random on each bit in the string. Otherwise, can can simply // mutate a known number of bits (based on the mutation rate). We don't check // to see how many bits we flip, nor do we keep track of which ones got flipped // so this can result in an actual mutation that is lower than that specified, // but the bigger the genome and the smaller the mutation probability, the // better the chance that it will match the desired mutation rate. // If nMut is greater than 1, then we round up, so a mutation of 2.2 would // be 3 mutations, and 2.9 would be 3 as well. nMut of 3 would be 3 mutations. int GA1DBinaryStringGenome::FlipMutator(GAGenome & c, float pmut) { GA1DBinaryStringGenome &child=DYN_CAST(GA1DBinaryStringGenome &, c); register int n, i; if(pmut <= 0.0) return(0); float nMut = pmut * STA_CAST(float, child.length()); if(nMut < 1.0){ // we have to do a flip test on each bit nMut = 0; for(i=child.length()-1; i>=0; i--){ if(GAFlipCoin(pmut)){ child.gene(i, ((child.gene(i) == 0) ? 1 : 0)); nMut++; } } } else{ // only flip the number of bits we need to flip for(n=0; n=0; i--) count += ((sis.gene(i) == bro.gene(i)) ? 0 : 1); return count/sis.length(); } // Randomly take bits from each parent. For each bit we flip a coin to see if // that bit should come from the mother or the father. This operator can be // used on genomes of different lengths, but the crossover is truncated to the // shorter of the parents and child. int GA1DBinaryStringGenome:: UniformCrossover(const GAGenome& p1, const GAGenome& p2, GAGenome* c1, GAGenome* c2){ const GA1DBinaryStringGenome &mom= DYN_CAST(const GA1DBinaryStringGenome &, p1); const GA1DBinaryStringGenome &dad= DYN_CAST(const GA1DBinaryStringGenome &, p2); int n=0; int i; if(c1 && c2){ GA1DBinaryStringGenome &sis=DYN_CAST(GA1DBinaryStringGenome &, *c1); GA1DBinaryStringGenome &bro=DYN_CAST(GA1DBinaryStringGenome &, *c2); if(sis.length() == bro.length() && mom.length() == dad.length() && sis.length() == mom.length()){ for(i=sis.length()-1; i>=0; i--){ if(GARandomBit()){ sis.gene(i, mom.gene(i)); bro.gene(i, dad.gene(i)); } else{ sis.gene(i, dad.gene(i)); bro.gene(i, mom.gene(i)); } } } else{ GAMask mask; int start; int max = (sis.length() > bro.length()) ? sis.length() : bro.length(); int min = (mom.length() < dad.length()) ? mom.length() : dad.length(); mask.size(max); for(i=0; i=0; i--) sis.gene(i, (mask[i] ? mom.gene(i) : dad.gene(i))); start = (bro.length() < min) ? bro.length()-1 : min-1; for(i=start; i>=0; i--) bro.gene(i, (mask[i] ? dad.gene(i) : mom.gene(i))); } n = 2; } else if(c1 || c2){ GA1DBinaryStringGenome &sis = (c1 ? DYN_CAST(GA1DBinaryStringGenome&, *c1) : DYN_CAST(GA1DBinaryStringGenome&, *c2)); if(mom.length() == dad.length() && sis.length() == mom.length()){ for(i=sis.length()-1; i>=0; i--) sis.gene(i, (GARandomBit() ? mom.gene(i) : dad.gene(i))); } else{ int min = (mom.length() < dad.length()) ? mom.length() : dad.length(); min = (sis.length() < min) ? sis.length() : min; for(i=min-1; i>=0; i--) sis.gene(i, (GARandomBit() ? mom.gene(i) : dad.gene(i))); } n = 1; } return n; } // Pick a point in the parents then grab alternating chunks for each child. // A word about crossover site mapping. If a genome has width 10, the // cross site can assume a value of 0 to 10, inclusive. A site of 0 means // that all of the material comes from the father. A site of 10 means that // all of the material comes from the mother. A site of 3 means that bits // 0-2 come from the mother and bits 3-9 come from the father. int GA1DBinaryStringGenome:: OnePointCrossover(const GAGenome& p1, const GAGenome& p2, GAGenome* c1, GAGenome* c2){ const GA1DBinaryStringGenome &mom= DYN_CAST(const GA1DBinaryStringGenome &, p1); const GA1DBinaryStringGenome &dad= DYN_CAST(const GA1DBinaryStringGenome &, p2); int n=0; unsigned int momsite, momlen; unsigned int dadsite, dadlen; if(c1 && c2){ GA1DBinaryStringGenome &sis=DYN_CAST(GA1DBinaryStringGenome &, *c1); GA1DBinaryStringGenome &bro=DYN_CAST(GA1DBinaryStringGenome &, *c2); if(sis.resizeBehaviour() == GAGenome::FIXED_SIZE && bro.resizeBehaviour() == GAGenome::FIXED_SIZE){ if(mom.length() != dad.length() || sis.length() != bro.length() || sis.length() != mom.length()){ GAErr(GA_LOC, mom.className(), "one-point cross", gaErrSameLengthReqd); return n; } momsite = dadsite = GARandomInt(0, mom.length()); momlen = dadlen = mom.length() - momsite; } else if(sis.resizeBehaviour() == GAGenome::FIXED_SIZE || bro.resizeBehaviour() == GAGenome::FIXED_SIZE){ GAErr(GA_LOC, mom.className(), "one-point cross", gaErrSameBehavReqd); return n; } else{ momsite = GARandomInt(0, mom.length()); dadsite = GARandomInt(0, dad.length()); momlen = mom.length() - momsite; dadlen = dad.length() - dadsite; sis.resize(momsite+dadlen); bro.resize(dadsite+momlen); } sis.copy(mom, 0, 0, momsite); sis.copy(dad, momsite, dadsite, dadlen); bro.copy(dad, 0, 0, dadsite); bro.copy(mom, dadsite, momsite, momlen); n = 2; } else if(c1 || c2){ GA1DBinaryStringGenome &sis = (c1 ? DYN_CAST(GA1DBinaryStringGenome&, *c1) : DYN_CAST(GA1DBinaryStringGenome&, *c2)); if(sis.resizeBehaviour() == GAGenome::FIXED_SIZE){ if(mom.length() != dad.length() || sis.length() != mom.length()){ GAErr(GA_LOC, mom.className(), "one-point cross", gaErrSameLengthReqd); return n; } momsite = dadsite = GARandomInt(0, mom.length()); momlen = dadlen = mom.length() - momsite; } else{ momsite = GARandomInt(0, mom.length()); dadsite = GARandomInt(0, dad.length()); momlen = mom.length() - momsite; dadlen = dad.length() - dadsite; sis.resize(momsite+dadlen); } if(GARandomBit()){ sis.copy(mom, 0, 0, momsite); sis.copy(dad, momsite, dadsite, dadlen); } else{ sis.copy(dad, 0, 0, dadsite); sis.copy(mom, dadsite, momsite, momlen); } n = 1; } return n; } // Two point crossover for one dimension binary strings. The first part is // taken from the mother, the second from the father, and the third from the // mother. If the child is resizable then we resize before copying the parts. // The rules for doing resizable crossover apply here as well as for the // single point crossover (see comments for 1Pt for details). int GA1DBinaryStringGenome:: TwoPointCrossover(const GAGenome& p1, const GAGenome& p2, GAGenome* c1, GAGenome* c2){ const GA1DBinaryStringGenome &mom= DYN_CAST(const GA1DBinaryStringGenome &, p1); const GA1DBinaryStringGenome &dad= DYN_CAST(const GA1DBinaryStringGenome &, p2); int n=0; unsigned int momsite[2], momlen[2]; unsigned int dadsite[2], dadlen[2]; if(c1 && c2){ GA1DBinaryStringGenome &sis=DYN_CAST(GA1DBinaryStringGenome &, *c1); GA1DBinaryStringGenome &bro=DYN_CAST(GA1DBinaryStringGenome &, *c2); if(sis.resizeBehaviour() == GAGenome::FIXED_SIZE && bro.resizeBehaviour() == GAGenome::FIXED_SIZE){ if(mom.length() != dad.length() || sis.length() != bro.length() || sis.length() != mom.length()){ GAErr(GA_LOC, mom.className(), "two-point cross", gaErrSameLengthReqd); return n; } momsite[0] = GARandomInt(0, mom.length()); momsite[1] = GARandomInt(0, mom.length()); if(momsite[0] > momsite[1]) SWAP(momsite[0], momsite[1]); momlen[0] = momsite[1] - momsite[0]; momlen[1] = mom.length() - momsite[1]; dadsite[0] = momsite[0]; dadsite[1] = momsite[1]; dadlen[0] = momlen[0]; dadlen[1] = momlen[1]; } else if(sis.resizeBehaviour() == GAGenome::FIXED_SIZE || bro.resizeBehaviour() == GAGenome::FIXED_SIZE){ GAErr(GA_LOC, mom.className(), "two-point cross", gaErrSameBehavReqd); return n; } else{ momsite[0] = GARandomInt(0, mom.length()); momsite[1] = GARandomInt(0, mom.length()); if(momsite[0] > momsite[1]) SWAP(momsite[0], momsite[1]); momlen[0] = momsite[1] - momsite[0]; momlen[1] = mom.length() - momsite[1]; dadsite[0] = GARandomInt(0, dad.length()); dadsite[1] = GARandomInt(0, dad.length()); if(dadsite[0] > dadsite[1]) SWAP(dadsite[0], dadsite[1]); dadlen[0] = dadsite[1] - dadsite[0]; dadlen[1] = dad.length() - dadsite[1]; sis.resize(momsite[0]+dadlen[0]+momlen[1]); bro.resize(dadsite[0]+momlen[0]+dadlen[1]); } sis.copy(mom, 0, 0, momsite[0]); sis.copy(dad, momsite[0], dadsite[0], dadlen[0]); sis.copy(mom, momsite[0]+dadlen[0], momsite[1], momlen[1]); bro.copy(dad, 0, 0, dadsite[0]); bro.copy(mom, dadsite[0], momsite[0], momlen[0]); bro.copy(dad, dadsite[0]+momlen[0], dadsite[1], dadlen[1]); n = 2; } else if(c1 || c2){ GA1DBinaryStringGenome &sis = (c1 ? DYN_CAST(GA1DBinaryStringGenome&, *c1) : DYN_CAST(GA1DBinaryStringGenome&, *c2)); if(sis.resizeBehaviour() == GAGenome::FIXED_SIZE){ if(mom.length() != dad.length() || sis.length() != mom.length()){ GAErr(GA_LOC, mom.className(), "two-point cross", gaErrSameLengthReqd); return n; } momsite[0] = GARandomInt(0, mom.length()); momsite[1] = GARandomInt(0, mom.length()); if(momsite[0] > momsite[1]) SWAP(momsite[0], momsite[1]); momlen[0] = momsite[1] - momsite[0]; momlen[1] = mom.length() - momsite[1]; dadsite[0] = momsite[0]; dadsite[1] = momsite[1]; dadlen[0] = momlen[0]; dadlen[1] = momlen[1]; } else{ momsite[0] = GARandomInt(0, mom.length()); momsite[1] = GARandomInt(0, mom.length()); if(momsite[0] > momsite[1]) SWAP(momsite[0], momsite[1]); momlen[0] = momsite[1] - momsite[0]; momlen[1] = mom.length() - momsite[1]; dadsite[0] = GARandomInt(0, dad.length()); dadsite[1] = GARandomInt(0, dad.length()); if(dadsite[0] > dadsite[1]) SWAP(dadsite[0], dadsite[1]); dadlen[0] = dadsite[1] - dadsite[0]; dadlen[1] = dad.length() - dadsite[1]; sis.resize(momsite[0]+dadlen[0]+momlen[1]); } if(GARandomBit()){ sis.copy(mom, 0, 0, momsite[0]); sis.copy(dad, momsite[0], dadsite[0], dadlen[0]); sis.copy(mom, momsite[0]+dadlen[0], momsite[1], momlen[1]); } else{ sis.copy(dad, 0, 0, dadsite[0]); sis.copy(mom, dadsite[0], momsite[0], momlen[0]); sis.copy(dad, dadsite[0]+momlen[0], dadsite[1], dadlen[1]); } n = 1; } return n; } // Even and odd crossovers take alternating bits from the mother and father. // For even crossover, we take every even bit from the mother and every odd bit // from the father (the first bit is the 0th bit, so it is even). Odd // crossover is just the opposite. int GA1DBinaryStringGenome:: EvenOddCrossover(const GAGenome& p1, const GAGenome& p2, GAGenome* c1, GAGenome* c2){ const GA1DBinaryStringGenome &mom= DYN_CAST(const GA1DBinaryStringGenome &, p1); const GA1DBinaryStringGenome &dad= DYN_CAST(const GA1DBinaryStringGenome &, p2); int n=0; int i; if(c1 && c2){ GA1DBinaryStringGenome &sis=DYN_CAST(GA1DBinaryStringGenome &, *c1); GA1DBinaryStringGenome &bro=DYN_CAST(GA1DBinaryStringGenome &, *c2); if(sis.length() == bro.length() && mom.length() == dad.length() && sis.length() == mom.length()){ for(i=sis.length()-1; i>=1; i-=2){ sis.gene(i, mom.gene(i)); bro.gene(i, dad.gene(i)); sis.gene(i-1, dad.gene(i-1)); bro.gene(i-1, mom.gene(i-1)); } if(i==0){ sis.gene(0, mom.gene(0)); bro.gene(0, dad.gene(0)); } } else{ int start; int min = (mom.length() < dad.length()) ? mom.length() : dad.length(); start = (sis.length() < min) ? sis.length()-1 : min-1; for(i=start; i>=0; i--) sis.gene(i, ((i%2 == 0) ? mom.gene(i) : dad.gene(i))); start = (bro.length() < min) ? bro.length()-1 : min-1; for(i=start; i>=0; i--) bro.gene(i, ((i%2 == 0) ? dad.gene(i) : mom.gene(i))); } n = 2; } else if(c1 || c2){ GA1DBinaryStringGenome &sis = (c1 ? DYN_CAST(GA1DBinaryStringGenome&, *c1) : DYN_CAST(GA1DBinaryStringGenome&, *c2)); if(mom.length() == dad.length() && sis.length() == mom.length()){ for(i=sis.length()-1; i>=1; i-=2){ sis.gene(i, mom.gene(i)); sis.gene(i-1, dad.gene(i-1)); } if(i==0){ sis.gene(0, mom.gene(0)); } } else{ int min = (mom.length() < dad.length()) ? mom.length() : dad.length(); min = (sis.length() < min) ? sis.length()-1 : min-1; for(i=min; i>=0; i--) sis.gene(i, ((i%2 == 0) ? mom.gene(i) : dad.gene(i))); } n = 1; } return n; } galib247/ga/GA1DBinStrGenome.h0100644003643600364360000001316110573535473015135 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- binstr1.h mbwall 19apr95 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved DESCRIPTION: This header defines the interface for the 1D binary string genome, including crossover objects and all the default and built-in operators. ---------------------------------------------------------------------------- */ #ifndef _ga_binstr1_h_ #define _ga_binstr1_h_ #include #include /* ---------------------------------------------------------------------------- 1DBinaryStringGenome ------------------------------------------------------------------------------- resize These genomes are resizable. In addition, you can set a resize behaviour to specify the bounds in which the resize can occur. copy Copy bits from the specified genome using the location and length that are passed to us. If the current genome is too short for the entire length, copy whatever we can. If the original genome is too short for the specified length, copy whatever we can. If either location is out of bounds, return without doing anything. We do NOT check for negative values in the locations! This routine clips if the copy sizes do not match - it does NOT resize the genome to fit the copy. You'll have to do resizes before you call this routine if you want the copy to fit the original. ==, != Are two genomes equal? Our test for equality is based upon the contents of the genome, NOT the behaviour. So as long as the bitstreams match, the genomes are 'equal'. This means that a resizeable genome may be equal to a fixed-length genome. But a chromsome with 500 bits allocated is not equal to a genome with 10 bits allocated unless both are the same size. ---------------------------------------------------------------------------- */ class GA1DBinaryStringGenome : public GABinaryString, public GAGenome { public: GADefineIdentity("GA1DBinaryStringGenome", GAID::BinaryStringGenome); static void UniformInitializer(GAGenome &); static void UnsetInitializer(GAGenome &); static void SetInitializer(GAGenome &); static int FlipMutator(GAGenome &, float); static int UniformCrossover(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*); static int EvenOddCrossover(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*); static int OnePointCrossover(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*); static int TwoPointCrossover(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*); static float BitComparator(const GAGenome&, const GAGenome&); public: GA1DBinaryStringGenome(unsigned int x, GAGenome::Evaluator f=(GAGenome::Evaluator)0, void * u=(void *)0); GA1DBinaryStringGenome(const GA1DBinaryStringGenome & orig); GA1DBinaryStringGenome& operator=(const GAGenome& arg) {copy(arg); return *this;} GA1DBinaryStringGenome& operator=(const short array []) // no err checks! {for(unsigned int i=0; i 0 && x < orig.nx && r < nx){ if(x + l > orig.nx) l = orig.nx - x; if(r + l > nx) l = nx - r; GABinaryString::copy(orig,r,x,l); } _evaluated = gaFalse; } inline void GA1DBinaryStringGenome::set(unsigned int x, unsigned int l){ if(x + l > nx) l = nx - x; GABinaryString::set(x, l); _evaluated = gaFalse; } inline void GA1DBinaryStringGenome::unset(unsigned int x, unsigned int l){ if(x + l > nx) l = nx - x; GABinaryString::unset(x, l); _evaluated = gaFalse; } inline void GA1DBinaryStringGenome::randomize(unsigned int x, unsigned int l){ if(x + l > nx) l = nx - x; GABinaryString::randomize(x, l); _evaluated = gaFalse; } inline void GA1DBinaryStringGenome::move(unsigned int x, unsigned int srcx,unsigned int l){ if(srcx + l > nx) l = nx - srcx; if(x + l > nx) l = nx - x; GABinaryString::move(x, srcx, l); _evaluated = gaFalse; } #endif galib247/ga/GA2DArrayGenome.C0100644003643600364360000005401710573535473014753 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- array2.C mbwall 25feb95 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved DESCRIPTION: Source file for the 2D array genome. ---------------------------------------------------------------------------- */ #ifndef _ga_array2_C_ #define _ga_array2_C_ #include #include #include #include #include #include /* ---------------------------------------------------------------------------- 2DArrayGenome ---------------------------------------------------------------------------- */ template const char * GA2DArrayGenome::className() const {return "GA2DArrayGenome";} template int GA2DArrayGenome::classID() const {return GAID::ArrayGenome2D;} template GA2DArrayGenome:: GA2DArrayGenome(unsigned int width, unsigned int height, GAGenome::Evaluator f, void * u) : GAArray(width*height), GAGenome(DEFAULT_2DARRAY_INITIALIZER, DEFAULT_2DARRAY_MUTATOR, DEFAULT_2DARRAY_COMPARATOR) { evaluator(f); userData(u); crossover(DEFAULT_2DARRAY_CROSSOVER); nx=minX=maxX=width; ny=minY=maxY=height; } template GA2DArrayGenome:: GA2DArrayGenome(const GA2DArrayGenome & orig) : GAArray(orig.sz){ GA2DArrayGenome::copy(orig); } template GA2DArrayGenome::~GA2DArrayGenome() { } template void GA2DArrayGenome::copy(const GAGenome & orig){ if(&orig == this) return; const GA2DArrayGenome* c = DYN_CAST(const GA2DArrayGenome*, &orig); if(c) { GAGenome::copy(*c); GAArray::copy(*c); nx = c->nx; ny = c->ny; minX = c->minX; minY = c->minY; maxX = c->maxX; maxY = c->maxY; } } template GAGenome * GA2DArrayGenome::clone(GAGenome::CloneMethod flag) const { GA2DArrayGenome *cpy = new GA2DArrayGenome(nx,ny); if(flag == CONTENTS){ cpy->copy(*this); } else{ cpy->GAGenome::copy(*this); cpy->minX = minX; cpy->minY = minY; cpy->maxX = maxX; cpy->maxY = maxY; } return cpy; } template int GA2DArrayGenome::resize(int w, int h){ if(w == STA_CAST(int,nx) && h == STA_CAST(int,ny)) return this->sz; if(w == GAGenome::ANY_SIZE) w = GARandomInt(minX, maxX); else if(w < 0) w = nx; // do nothing else if(minX == maxX) minX=maxX = w; else{ if(w < STA_CAST(int,minX)) w=minX; if(w > STA_CAST(int,maxX)) w=maxX; } if(h == GAGenome::ANY_SIZE) h = GARandomInt(minY, maxY); else if(h < 0) h = ny; // do nothing else if(minY == maxY) minY=maxY = h; else{ if(h < STA_CAST(int,minY)) h=minY; if(h > STA_CAST(int,maxY)) h=maxY; } if(w < STA_CAST(int,nx)){ int y=GAMin(STA_CAST(int,ny),h); for(int j=0; j::move(j*w,j*nx,w); } GAArray::size(w*h); if(w > STA_CAST(int,nx)){ // adjust the existing chunks of bits int y=GAMin(STA_CAST(int,ny),h); for(int j=y-1; j>=0; j--) GAArray::move(j*w,j*nx,nx); } nx = w; ny = h; _evaluated = gaFalse; return this->sz; } #ifdef GALIB_USE_STREAMS template int GA2DArrayGenome::read(STD_ISTREAM &) { GAErr(GA_LOC, className(), "read", gaErrOpUndef); return 1; } template int GA2DArrayGenome::write(STD_OSTREAM & os) const { for(unsigned int j=0; j int GA2DArrayGenome::resizeBehaviour(GAGenome::Dimension which) const { int val = 0; if(which == WIDTH) { if(maxX == minX) val = FIXED_SIZE; else val = maxX; } else if(which == HEIGHT) { if(maxY == minY) val = FIXED_SIZE; else val = maxY; } return val; } template int GA2DArrayGenome:: resizeBehaviour(GAGenome::Dimension which, unsigned int lower, unsigned int upper) { if(upper < lower){ GAErr(GA_LOC, className(), "resizeBehaviour", gaErrBadResizeBehaviour); return resizeBehaviour(which); } switch(which){ case WIDTH: minX = lower; maxX = upper; if(nx > upper) GA2DArrayGenome::resize(upper,ny); if(nx < lower) GA2DArrayGenome::resize(lower,ny); break; case HEIGHT: minY = lower; maxY = upper; if(ny > upper) GA2DArrayGenome::resize(nx,upper); if(ny < lower) GA2DArrayGenome::resize(nx,lower); break; default: break; } return resizeBehaviour(which); } template void GA2DArrayGenome::copy(const GA2DArrayGenome & orig, unsigned int r, unsigned int s, unsigned int x, unsigned int y, unsigned int w, unsigned int h) { if(w == 0 || x >= orig.nx || r >= nx || h == 0 || y >= orig.ny || s >= ny) return; if(x + w > orig.nx) w = orig.nx - x; if(y + h > orig.ny) h = orig.ny - y; if(r + w > nx) w = nx - r; if(s + h > ny) h = ny - s; for(unsigned int j=0; j::copy(orig, (s+j)*nx+r, (y+j)*orig.nx+x, w); _evaluated = gaFalse; } template int GA2DArrayGenome::equal(const GAGenome & c) const { if(this == &c) return 1; GA2DArrayGenome & b = (GA2DArrayGenome &)c; if(nx != b.nx || ny != b.ny) return 0; int val=0; for(unsigned int j=0; j::equal(b,j*nx,j*nx,nx) ? 0 : 1; return(val ? 0 : 1); } /* ---------------------------------------------------------------------------- 2DArrayAlleleGenome ---------------------------------------------------------------------------- */ template const char * GA2DArrayAlleleGenome::className() const {return "GA2DArrayAlleleGenome";} template int GA2DArrayAlleleGenome::classID() const {return GAID::ArrayAlleleGenome2D;} template GA2DArrayAlleleGenome:: GA2DArrayAlleleGenome(unsigned int width, unsigned int height, const GAAlleleSet & s, GAGenome::Evaluator f, void * u) : GA2DArrayGenome(width,height,f,u){ naset = 1; aset = new GAAlleleSet[1]; aset[0] = s; initializer(GA2DArrayAlleleGenome::DEFAULT_2DARRAY_ALLELE_INITIALIZER); mutator(GA2DArrayAlleleGenome::DEFAULT_2DARRAY_ALLELE_MUTATOR); comparator(GA2DArrayAlleleGenome::DEFAULT_2DARRAY_ALLELE_COMPARATOR); crossover(GA2DArrayAlleleGenome::DEFAULT_2DARRAY_ALLELE_CROSSOVER); } template GA2DArrayAlleleGenome:: GA2DArrayAlleleGenome(unsigned int width, unsigned int height, const GAAlleleSetArray & sa, GAGenome::Evaluator f, void * u) : GA2DArrayGenome(width,height, f, u) { naset = sa.size(); aset = new GAAlleleSet[naset]; for(int i=0; i::DEFAULT_2DARRAY_ALLELE_INITIALIZER); mutator(GA2DArrayAlleleGenome::DEFAULT_2DARRAY_ALLELE_MUTATOR); comparator(GA2DArrayAlleleGenome::DEFAULT_2DARRAY_ALLELE_COMPARATOR); crossover(GA2DArrayAlleleGenome::DEFAULT_2DARRAY_ALLELE_CROSSOVER); } template GA2DArrayAlleleGenome:: GA2DArrayAlleleGenome(const GA2DArrayAlleleGenome & orig) : GA2DArrayGenome(orig.nx, orig.ny) { naset = 0; aset = (GAAlleleSet*)0; GA2DArrayAlleleGenome::copy(orig); } template GA2DArrayAlleleGenome::~GA2DArrayAlleleGenome(){ delete [] aset; } template GAGenome * GA2DArrayAlleleGenome::clone(GAGenome::CloneMethod) const { return new GA2DArrayAlleleGenome(*this); } template void GA2DArrayAlleleGenome::copy(const GAGenome& orig){ if(&orig == this) return; const GA2DArrayAlleleGenome* c = DYN_CAST(const GA2DArrayAlleleGenome*, &orig); if(c) { GA2DArrayGenome::copy(*c); if(naset != c->naset){ delete [] aset; naset = c->naset; aset = new GAAlleleSet[c->naset]; } for(int i=0; iaset[i]); } } template int GA2DArrayAlleleGenome::resize(int x, int y){ unsigned int oldx = this->nx; unsigned int oldy = this->ny; GA2DArrayGenome::resize(x,y); if(this->nx > oldx){ // adjust the existing chunks of bits int y=GAMin(oldy,this->ny); for(int j=y-1; j>=0; j--){ for(unsigned int i=oldx; inx; i++) this->a[j * this->nx+i] = aset[(j * this->nx+i) % naset].allele(); } } if(this->ny > oldy){ // change in height is always new bits for(unsigned int i=this->nx*oldy; inx * this->ny; i++) this->a[i] = aset[i % naset].allele(); } return this->sz; } #ifdef GALIB_USE_STREAMS template int GA2DArrayAlleleGenome::read(STD_ISTREAM& is){ return GA2DArrayGenome::read(is); } template int GA2DArrayAlleleGenome::write(STD_OSTREAM& os) const { return GA2DArrayGenome::write(os); } #endif template int GA2DArrayAlleleGenome::equal(const GAGenome & c) const { return GA2DArrayGenome::equal(c); } /* ---------------------------------------------------------------------------- Operator definitions ---------------------------------------------------------------------------- */ // this does not handle genomes with multiple allele sets! template void GA2DArrayAlleleGenome::UniformInitializer(GAGenome & c) { GA2DArrayAlleleGenome &child= DYN_CAST(GA2DArrayAlleleGenome &, c); child.resize(GAGenome::ANY_SIZE,GAGenome::ANY_SIZE); for(int i=child.width()-1; i>=0; i--) for(int j=child.height()-1; j>=0; j--) child.gene(i, j, child.alleleset().allele()); } template int GA2DArrayAlleleGenome::FlipMutator(GAGenome & c, float pmut) { GA2DArrayAlleleGenome &child= DYN_CAST(GA2DArrayAlleleGenome &, c); register int n, m, i, j; if(pmut <= 0.0) return(0); float nMut = pmut * STA_CAST(float,child.size()); if(nMut < 1.0){ // we have to do a flip test on each bit nMut = 0; for(i=child.width()-1; i>=0; i--){ for(j=child.height()-1; j>=0; j--){ if(GAFlipCoin(pmut)){ child.gene(i, j, child.alleleset().allele()); nMut++; } } } } else{ // only flip the number of bits we need to flip for(n=0; n int GA2DArrayGenome::SwapMutator(GAGenome & c, float pmut) { GA2DArrayGenome &child=DYN_CAST(GA2DArrayGenome&, c); register int n, i; if(pmut <= 0.0) return(0); float nMut = pmut * STA_CAST(float,child.size()); int size = child.size()-1; if(nMut < 1.0){ // we have to do a flip test on each bit nMut = 0; for(i=size; i>=0; i--){ if(GAFlipCoin(pmut)){ child.GAArray::swap(i, GARandomInt(0, size)); nMut++; } } } else{ // only flip the number of bits we need to flip for(n=0; n::swap(GARandomInt(0,size),GARandomInt(0,size)); } return(STA_CAST(int,nMut)); } template float GA2DArrayGenome:: ElementComparator(const GAGenome& a, const GAGenome& b) { const GA2DArrayGenome& sis= DYN_CAST(const GA2DArrayGenome&, a); const GA2DArrayGenome& bro= DYN_CAST(const GA2DArrayGenome&, b); if(sis.size() != bro.size()) return -1; if(sis.size() == 0) return 0; float count = 0.0; for(int i=sis.width()-1; i>=0; i--) for(int j=sis.height()-1; j>=0; j--) count += ((sis.gene(i,j) == bro.gene(i,j)) ? 0 : 1); return count/sis.size(); } template int GA2DArrayGenome:: UniformCrossover(const GAGenome& p1, const GAGenome& p2, GAGenome* c1, GAGenome* c2){ const GA2DArrayGenome &mom=DYN_CAST(const GA2DArrayGenome &, p1); const GA2DArrayGenome &dad=DYN_CAST(const GA2DArrayGenome &, p2); int nc=0; int i,j; if(c1 && c2){ GA2DArrayGenome &sis=DYN_CAST(GA2DArrayGenome &, *c1); GA2DArrayGenome &bro=DYN_CAST(GA2DArrayGenome &, *c2); if(sis.width() == bro.width() && sis.height() == bro.height() && mom.width() == dad.width() && mom.height() == dad.height() && sis.width() == mom.width() && sis.height() == mom.height()){ for(i=sis.width()-1; i>=0; i--){ for(j=sis.height()-1; j>=0; j--){ if(GARandomBit()){ sis.gene(i,j, mom.gene(i,j)); bro.gene(i,j, dad.gene(i,j)); } else{ sis.gene(i,j, dad.gene(i,j)); bro.gene(i,j, mom.gene(i,j)); } } } } else{ GAMask mask; int startx, starty; int maxx = (sis.width() > bro.width()) ? sis.width() : bro.width(); int minx = (mom.width() < dad.width()) ? mom.width() : dad.width(); int maxy = (sis.height() > bro.height()) ? sis.height() : bro.height(); int miny = (mom.height() < dad.height()) ? mom.height() : dad.height(); mask.size(maxx*maxy); for(i=0; i=0; i--) for(j=starty-1; j>=0; j--) sis.gene(i,j, (mask[i*starty+j] ? mom.gene(i,j) : dad.gene(i,j))); startx = (bro.width() < minx) ? bro.width() : minx; starty = (bro.height() < miny) ? bro.height() : miny; for(i=startx-1; i>=0; i--) for(j=starty-1; j>=0; j--) bro.gene(i,j, (mask[i*starty+j] ? dad.gene(i,j) : mom.gene(i,j))); } nc = 2; } else if(c1){ GA2DArrayGenome &sis=DYN_CAST(GA2DArrayGenome &, *c1); if(mom.width() == dad.width() && mom.height() == dad.height() && sis.width() == mom.width() && sis.height() == mom.height()){ for(i=sis.width()-1; i>=0; i--) for(j=sis.height()-1; j>=0; j--) sis.gene(i,j, (GARandomBit() ? mom.gene(i,j) : dad.gene(i,j))); } else{ int minx = (mom.width() < dad.width()) ? mom.width() : dad.width(); int miny = (mom.height() < dad.height()) ? mom.height() : dad.height(); minx = (sis.width() < minx) ? sis.width() : minx; miny = (sis.height() < miny) ? sis.height() : miny; for(i=minx-1; i>=0; i--) for(j=miny-1; j>=0; j--) sis.gene(i,j, (GARandomBit() ? mom.gene(i,j) : dad.gene(i,j))); } nc = 1; } return nc; } // This crossover does clipping (no padding) for resizables. Notice that this // means that any resizable children of two parents will have identical // dimensions no matter what. template int GA2DArrayGenome:: OnePointCrossover(const GAGenome& p1, const GAGenome& p2, GAGenome* c1, GAGenome* c2){ const GA2DArrayGenome &mom=DYN_CAST(const GA2DArrayGenome &, p1); const GA2DArrayGenome &dad=DYN_CAST(const GA2DArrayGenome &, p2); int nc=0; unsigned int momsitex, momlenx, momsitey, momleny; unsigned int dadsitex, dadlenx, dadsitey, dadleny; unsigned int sitex, lenx, sitey, leny; if(c1 && c2){ GA2DArrayGenome &sis=DYN_CAST(GA2DArrayGenome &, *c1); GA2DArrayGenome &bro=DYN_CAST(GA2DArrayGenome &, *c2); if(sis.resizeBehaviour(GAGenome::WIDTH) == GAGenome::FIXED_SIZE && bro.resizeBehaviour(GAGenome::WIDTH) == GAGenome::FIXED_SIZE){ if(mom.width() != dad.width() || sis.width() != bro.width() || sis.width() != mom.width()){ GAErr(GA_LOC, mom.className(), "one-point cross", gaErrSameLengthReqd); return nc; } sitex = momsitex = dadsitex = GARandomInt(0, mom.width()); lenx = momlenx = dadlenx = mom.width() - momsitex; } else if(sis.resizeBehaviour(GAGenome::WIDTH) == GAGenome::FIXED_SIZE || bro.resizeBehaviour(GAGenome::WIDTH) == GAGenome::FIXED_SIZE){ GAErr(GA_LOC, mom.className(), "one-point cross", gaErrSameBehavReqd); return nc; } else{ momsitex = GARandomInt(0, mom.width()); dadsitex = GARandomInt(0, dad.width()); momlenx = mom.width() - momsitex; dadlenx = dad.width() - dadsitex; sitex = GAMin(momsitex, dadsitex); lenx = GAMin(momlenx, dadlenx); } if(sis.resizeBehaviour(GAGenome::HEIGHT) == GAGenome::FIXED_SIZE && bro.resizeBehaviour(GAGenome::HEIGHT) == GAGenome::FIXED_SIZE){ if(mom.height() != dad.height() || sis.height() != bro.height() || sis.height() != mom.height()){ GAErr(GA_LOC, mom.className(), "one-point cross", gaErrSameLengthReqd); return nc; } sitey = momsitey = dadsitey = GARandomInt(0, mom.height()); leny = momleny = dadleny = mom.height() - momsitey; } else if(sis.resizeBehaviour(GAGenome::HEIGHT) == GAGenome::FIXED_SIZE || bro.resizeBehaviour(GAGenome::HEIGHT) == GAGenome::FIXED_SIZE){ GAErr(GA_LOC, mom.className(), "one-point cross", gaErrSameBehavReqd); return nc; } else{ momsitey = GARandomInt(0, mom.height()); dadsitey = GARandomInt(0, dad.height()); momleny = mom.height() - momsitey; dadleny = dad.height() - dadsitey; sitey = GAMin(momsitey, dadsitey); leny = GAMin(momleny, dadleny); } sis.resize(sitex+lenx, sitey+leny); bro.resize(sitex+lenx, sitey+leny); sis.copy(mom, 0, 0, momsitex-sitex, momsitey-sitey, sitex, sitey); sis.copy(dad, sitex, 0, dadsitex, dadsitey-sitey, lenx, sitey); sis.copy(dad, 0, sitey, dadsitex-sitex, dadsitey, sitex, leny); sis.copy(mom, sitex, sitey, momsitex, momsitey, lenx, leny); bro.copy(dad, 0, 0, dadsitex-sitex, dadsitey-sitey, sitex, sitey); bro.copy(mom, sitex, 0, momsitex, momsitey-sitey, lenx, sitey); bro.copy(mom, 0, sitey, momsitex-sitex, momsitey, sitex, leny); bro.copy(dad, sitex, sitey, dadsitex, dadsitey, lenx, leny); nc = 2; } else if(c1){ GA2DArrayGenome &sis=DYN_CAST(GA2DArrayGenome &, *c1); if(sis.resizeBehaviour(GAGenome::WIDTH) == GAGenome::FIXED_SIZE){ if(mom.width() != dad.width() || sis.width() != mom.width()){ GAErr(GA_LOC, mom.className(), "one-point cross", gaErrSameLengthReqd); return nc; } sitex = momsitex = dadsitex = GARandomInt(0, mom.width()); lenx = momlenx = dadlenx = mom.width() - momsitex; } else{ momsitex = GARandomInt(0, mom.width()); dadsitex = GARandomInt(0, dad.width()); momlenx = mom.width() - momsitex; dadlenx = dad.width() - dadsitex; sitex = GAMin(momsitex, dadsitex); lenx = GAMin(momlenx, dadlenx); } if(sis.resizeBehaviour(GAGenome::HEIGHT) == GAGenome::FIXED_SIZE){ if(mom.height() != dad.height() || sis.height() != mom.height()){ GAErr(GA_LOC, mom.className(), "one-point cross", gaErrSameLengthReqd); return nc; } sitey = momsitey = dadsitey = GARandomInt(0, mom.height()); leny = momleny = dadleny = mom.height() - momsitey; } else{ momsitey = GARandomInt(0, mom.height()); dadsitey = GARandomInt(0, dad.height()); momleny = mom.height() - momsitey; dadleny = dad.height() - dadsitey; sitey = GAMin(momsitey, dadsitey); leny = GAMin(momleny, dadleny); } sis.resize(sitex+lenx, sitey+leny); if(GARandomBit()){ sis.copy(mom, 0, 0, momsitex-sitex, momsitey-sitey, sitex, sitey); sis.copy(dad, sitex, 0, dadsitex, dadsitey-sitey, lenx, sitey); sis.copy(dad, 0, sitey, dadsitex-sitex, dadsitey, sitex, leny); sis.copy(mom, sitex, sitey, momsitex, momsitey, lenx, leny); } else{ sis.copy(dad, 0, 0, dadsitex-sitex, dadsitey-sitey, sitex, sitey); sis.copy(mom, sitex, 0, momsitex, momsitey-sitey, lenx, sitey); sis.copy(mom, 0, sitey, momsitex-sitex, momsitey, sitex, leny); sis.copy(dad, sitex, sitey, dadsitex, dadsitey, lenx, leny); } nc = 1; } return nc; } template int GA2DArrayGenome:: EvenOddCrossover(const GAGenome& p1, const GAGenome& p2, GAGenome* c1, GAGenome* c2){ const GA2DArrayGenome &mom=DYN_CAST(const GA2DArrayGenome &, p1); const GA2DArrayGenome &dad=DYN_CAST(const GA2DArrayGenome &, p2); int nc=0; int i,j; if(c1 && c2){ GA2DArrayGenome &sis=DYN_CAST(GA2DArrayGenome &, *c1); GA2DArrayGenome &bro=DYN_CAST(GA2DArrayGenome &, *c2); if(sis.width() == bro.width() && sis.height() == bro.height() && mom.width() == dad.width() && mom.height() == dad.height() && sis.width() == mom.width() && sis.height() == mom.height()){ int count=0; for(i=sis.width()-1; i>=0; i--){ for(j=sis.height()-1; j>=0; j--){ sis.gene(i,j, ((count%2 == 0) ? mom.gene(i,j) : dad.gene(i,j))); bro.gene(i,j, ((count%2 == 0) ? dad.gene(i,j) : mom.gene(i,j))); count++; } } } else{ int startx, starty; int minx = (mom.width() < dad.width()) ? mom.width() : dad.width(); int miny = (mom.height() < dad.height()) ? mom.height() : dad.height(); startx = (sis.width() < minx) ? sis.width() : minx; starty = (sis.height() < miny) ? sis.height() : miny; for(i=startx-1; i>=0; i--) for(j=starty-1; j>=0; j--) sis.gene(i,j, (((i*starty+j)%2 == 0) ? mom.gene(i,j):dad.gene(i,j))); startx = (bro.width() < minx) ? bro.width() : minx; starty = (bro.height() < miny) ? bro.height() : miny; for(i=startx-1; i>=0; i--) for(j=starty-1; j>=0; j--) bro.gene(i,j, (((i*starty+j)%2 == 0) ? dad.gene(i,j):mom.gene(i,j))); } nc = 2; } else if(c1){ GA2DArrayGenome &sis=DYN_CAST(GA2DArrayGenome &, *c1); if(mom.width() == dad.width() && mom.height() == dad.height() && sis.width() == mom.width() && sis.height() == mom.height()){ int count=0; for(i=sis.width()-1; i>=0; i--){ for(j=sis.height()-1; j>=0; j--){ sis.gene(i,j, ((count%2 == 0) ? mom.gene(i,j) : dad.gene(i,j))); count++; } } } else{ int minx = (mom.width() < dad.width()) ? mom.width() : dad.width(); int miny = (mom.height() < dad.height()) ? mom.height() : dad.height(); minx = (sis.width() < minx) ? sis.width() : minx; miny = (sis.height() < miny) ? sis.height() : miny; for(i=minx-1; i>=0; i--) for(j=miny-1; j>=0; j--) sis.gene(i,j, (((i*miny+j)%2 == 0) ? mom.gene(i,j) : dad.gene(i,j))); } nc = 1; } return nc; } #endif galib247/ga/GA2DArrayGenome.h0100644003643600364360000001123010573535473015006 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- array2.h mbwall 25feb95 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved DESCRIPTION: This header defines the interface for the 2D array genome. See comments in 1D array file. ---------------------------------------------------------------------------- */ #ifndef _ga_array2_h_ #define _ga_array2_h_ #include #include #include /* ---------------------------------------------------------------------------- 2DArrayGenome ---------------------------------------------------------------------------- */ template class GA2DArrayGenome : public GAArray, public GAGenome { public: GADeclareIdentity(); static int SwapMutator(GAGenome&, float); static float ElementComparator(const GAGenome&, const GAGenome&); static int UniformCrossover(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*); static int EvenOddCrossover(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*); static int OnePointCrossover(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*); public: GA2DArrayGenome(unsigned int x, unsigned int y, GAGenome::Evaluator f=(GAGenome::Evaluator)0, void * u=(void *)0); GA2DArrayGenome(const GA2DArrayGenome & orig); GA2DArrayGenome& operator=(const GAGenome& orig) {copy(orig); return *this;} GA2DArrayGenome& operator=(const T array []){ for(unsigned int i=0; ia[y*nx+x]; } T & gene(unsigned int x, unsigned int y, const T & value) { if(this->a[y*nx+x] != value) { this->a[y*nx+x] = value; _evaluated = gaFalse; } return this->a[y*nx+x]; } int width() const {return nx;} int width(int w){resize(w, ny); return nx;} int height() const {return ny;} int height(int h){resize(nx, h); return ny;} virtual int resize(int x, int y); int resizeBehaviour(Dimension which) const; int resizeBehaviour(Dimension which, unsigned int lower, unsigned int upper); int resizeBehaviour(unsigned int lowerX, unsigned int upperX, unsigned int lowerY, unsigned int upperY){ return(resizeBehaviour(WIDTH, lowerX, upperX) * resizeBehaviour(HEIGHT, lowerY, upperY)); } void copy(const GA2DArrayGenome &, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int); void swap(unsigned int a, unsigned int b, unsigned int c, unsigned int d){ GAArray::swap(b*nx+a, d*nx+c); _evaluated = gaFalse; } protected: GAAlleleSet * as; // the allele set unsigned int nx, ny, minX, minY, maxX, maxY; }; /* ---------------------------------------------------------------------------- 2DArrayAlleleGenome ---------------------------------------------------------------------------- */ template class GA2DArrayAlleleGenome : public GA2DArrayGenome { public: GADeclareIdentity(); static void UniformInitializer(GAGenome&); static int FlipMutator(GAGenome&, float); public: GA2DArrayAlleleGenome(unsigned int x, unsigned int y, const GAAlleleSet & a, GAGenome::Evaluator f=(GAGenome::Evaluator)0, void * u=(void *)0); GA2DArrayAlleleGenome(unsigned int x, unsigned int y, const GAAlleleSetArray & a, GAGenome::Evaluator f=(GAGenome::Evaluator)0, void * u=(void *)0); GA2DArrayAlleleGenome(const GA2DArrayAlleleGenome & orig); GA2DArrayAlleleGenome& operator=(const GAGenome& orig) {copy(orig); return *this;} GA2DArrayAlleleGenome& operator=(const T array []) { GA2DArrayGenome::operator=(array); return *this; } virtual ~GA2DArrayAlleleGenome(); virtual GAGenome * clone(GAGenome::CloneMethod flag=GAGenome::CONTENTS) const; virtual void copy(const GAGenome &); #ifdef GALIB_USE_STREAMS virtual int read(STD_ISTREAM & is); virtual int write (STD_OSTREAM & os) const ; #endif int equal(const GAGenome & c) const ; virtual int resize(int x, int y); const GAAlleleSet& alleleset(unsigned int i=0) const {return aset[i%naset];} protected: int naset; GAAlleleSet * aset; }; #ifdef GALIB_USE_BORLAND_INST #include #endif #endif galib247/ga/GA2DBinStrGenome.C0100644003643600364360000005161110573535474015074 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- binstr2.C mbwall 19apr95 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved DESCRIPTION: Source file for the 2D binary string genome. See the 1D genome for comments. ---------------------------------------------------------------------------- */ #include #include #include #include #include #include #include #include /* ---------------------------------------------------------------------------- Genome class definition ---------------------------------------------------------------------------- */ GA2DBinaryStringGenome:: GA2DBinaryStringGenome(unsigned int width, unsigned int height, GAGenome::Evaluator f, void * u) : GABinaryString(width*height), GAGenome(DEFAULT_2DBINSTR_INITIALIZER, DEFAULT_2DBINSTR_MUTATOR, DEFAULT_2DBINSTR_COMPARATOR) { evaluator(f); userData(u); crossover(DEFAULT_2DBINSTR_CROSSOVER); nx=minX=maxX=0; ny=minY=maxY=0; resize(width, height); } GA2DBinaryStringGenome:: GA2DBinaryStringGenome(const GA2DBinaryStringGenome & orig) : GABinaryString(orig.GABinaryString::size()), GAGenome() { nx=minX=maxX=0; ny=minY=maxY=0; GA2DBinaryStringGenome::copy(orig); } GA2DBinaryStringGenome::~GA2DBinaryStringGenome() { } GAGenome * GA2DBinaryStringGenome::clone(GAGenome::CloneMethod flag) const { GA2DBinaryStringGenome *cpy = new GA2DBinaryStringGenome(nx,ny); if(flag == CONTENTS){ cpy->copy(*this); } else{ cpy->GAGenome::copy(*this); cpy->minX = minX; cpy->minY = minY; cpy->maxX = maxX; cpy->maxY = maxY; } return cpy; } void GA2DBinaryStringGenome::copy(const GAGenome & orig) { if(&orig == this) return; const GA2DBinaryStringGenome* c = DYN_CAST(const GA2DBinaryStringGenome*, &orig); if(c) { GAGenome::copy(*c); GABinaryString::copy(*c); nx = c->nx; ny = c->ny; minX = c->minX; minY = c->minY; maxX = c->maxX; maxY = c->maxY; } } int GA2DBinaryStringGenome::resize(int w, int h) { if((unsigned int)w == nx && (unsigned int)h == ny) return sz; if(w == GAGenome::ANY_SIZE) w = GARandomInt(minX, maxX); else if(w < 0) w = nx; // do nothing else if(minX == maxX) minX=maxX = w; else{ if(w < STA_CAST(int, minX)) w=minX; if(w > STA_CAST(int, maxX)) w=maxX; } if(h == GAGenome::ANY_SIZE) h = GARandomInt(minY, maxY); else if(h < 0) h = ny; // do nothing else if(minY == maxY) minY=maxY = h; else{ if(h < STA_CAST(int, minY)) h=minY; if(h > STA_CAST(int, maxY)) h=maxY; } // Move the bits into the right position. If we're smaller, then shift to // the smaller size before we do the resize (the resize method maintains bit // integrety). If we're larger, do the move after the resize. If we're the // same size the we don't do anything. When we're adding more bits, the new // bits get set randomly to 0 or 1. if(w < STA_CAST(int,nx)){ int y=GAMin(STA_CAST(int,ny),h); for(int j=0; j STA_CAST(int,nx)){ // adjust the existing chunks of bits int y=GAMin(STA_CAST(int,ny),h); for(int j=y-1; j>=0; j--){ GABinaryString::move(j*w,j*nx,nx); for(int i=nx; i STA_CAST(int,ny)){ // change in height is always new bits for(int i=w*ny; i> c; if(isdigit(c)){ gene(i, j, ((c == '0') ? 0 : 1)); if(++i >= nx){ // ready for next row i=0; j++; } } } _evaluated = gaFalse; if(is.eof() && ((j < ny) || // didn't get some lines (i < nx && i != 0))){ // stopped early on a row GAErr(GA_LOC, className(), "read", gaErrUnexpectedEOF); is.clear(STD_IOS_BADBIT | is.rdstate()); return 1; } return 0; } // Dump the digits to the stream with a newline between each row. No newline // at the end of the whole thing. int GA2DBinaryStringGenome::write(STD_OSTREAM & os) const { for(unsigned int j=0; j upper) resize(upper,ny); if(nx < lower) resize(lower,ny); break; case HEIGHT: minY = lower; maxY = upper; if(ny > upper) resize(nx,upper); if(ny < lower) resize(nx,lower); break; default: break; } return resizeBehaviour(which); } void GA2DBinaryStringGenome::copy(const GA2DBinaryStringGenome & orig, unsigned int r, unsigned int s, unsigned int x, unsigned int y, unsigned int w, unsigned int h) { if(w == 0 || x >= orig.nx || r >= nx || h == 0 || y >= orig.ny || s >= ny) return; if(x + w > orig.nx) w = orig.nx - x; if(y + h > orig.ny) h = orig.ny - y; if(r + w > nx) w = nx - r; if(s + h > ny) h = ny - s; for(unsigned int j=0; j nx) w = nx - x; if(y + h > ny) h = ny - y; for(unsigned int j=0; j nx) w = nx - x; if(y + h > ny) h = ny - y; for(unsigned int j=0; j nx) w = nx - x; if(y + h > ny) h = ny - y; for(unsigned int j=0; j nx) w = nx - srcx; if(x + w > nx) w = nx - x; if(srcy + h > ny) h = ny - srcy; if(y + h > ny) h = ny - y; if(srcy=0; j--) GABinaryString::move((y+j)*nx+x, (srcy+j)*nx+srcx, w); } else{ for(unsigned int j=0; j=0; i--) for(int j=child.height()-1; j>=0; j--) child.gene(i, j, GARandomBit()); } void GA2DBinaryStringGenome::UnsetInitializer(GAGenome & c) { GA2DBinaryStringGenome &child=DYN_CAST(GA2DBinaryStringGenome &, c); child.resize(GAGenome::ANY_SIZE, GAGenome::ANY_SIZE); child.unset(0, 0, child.width(), child.height()); } void GA2DBinaryStringGenome::SetInitializer(GAGenome & c) { GA2DBinaryStringGenome &child=DYN_CAST(GA2DBinaryStringGenome &, c); child.resize(GAGenome::ANY_SIZE, GAGenome::ANY_SIZE); child.set(0, 0, child.width(), child.height()); } int GA2DBinaryStringGenome::FlipMutator(GAGenome & c, float pmut) { GA2DBinaryStringGenome &child=DYN_CAST(GA2DBinaryStringGenome &, c); register int n, m, i, j; if(pmut <= 0.0) return(0); float nMut = pmut * STA_CAST(float, child.size()); if(nMut < 1.0){ // we have to do a flip test on each bit nMut = 0; for(i=child.width()-1; i>=0; i--){ for(j=child.height()-1; j>=0; j--){ if(GAFlipCoin(pmut)){ child.gene(i, j, ((child.gene(i,j) == 0) ? 1 : 0)); nMut++; } } } } else{ // only flip the number of bits we need to flip for(n=0; n=0; i--) for(int j=sis.height()-1; j>=0; j--) count += ((sis.gene(i,j) == bro.gene(i,j)) ? 0 : 1); return count/sis.size(); } int GA2DBinaryStringGenome:: UniformCrossover(const GAGenome& p1, const GAGenome& p2, GAGenome* c1, GAGenome* c2){ const GA2DBinaryStringGenome &mom= DYN_CAST(const GA2DBinaryStringGenome &, p1); const GA2DBinaryStringGenome &dad= DYN_CAST(const GA2DBinaryStringGenome &, p2); int nc=0; int i,j; if(c1 && c2){ GA2DBinaryStringGenome &sis=DYN_CAST(GA2DBinaryStringGenome &, *c1); GA2DBinaryStringGenome &bro=DYN_CAST(GA2DBinaryStringGenome &, *c2); if(sis.width() == bro.width() && sis.height() == bro.height() && mom.width() == dad.width() && mom.height() == dad.height() && sis.width() == mom.width() && sis.height() == mom.height()){ for(i=sis.width()-1; i>=0; i--){ for(j=sis.height()-1; j>=0; j--){ if(GARandomBit()){ sis.gene(i,j, mom.gene(i,j)); bro.gene(i,j, dad.gene(i,j)); } else{ sis.gene(i,j, dad.gene(i,j)); bro.gene(i,j, mom.gene(i,j)); } } } } else{ GAMask mask; int maxx = GAMax(sis.width(), bro.width()); int minx = GAMin(mom.width(), dad.width()); int maxy = GAMax(sis.height(), bro.height()); int miny = GAMin(mom.height(), dad.height()); mask.size(maxx*maxy); for(i=0; i=0; i--) for(j=sis.height()-1; j>=0; j--) sis.gene(i,j, (GARandomBit() ? mom.gene(i,j) : dad.gene(i,j))); } else{ int minx = GAMin(mom.width(), dad.width()); int miny = GAMin(mom.height(), dad.height()); minx = GAMin(sis.width(), minx); miny = GAMin(sis.height(), miny); for(i=0; i=0; i--){ for(j=sis.height()-1; j>=0; j--){ if(count%2 == 0){ sis.gene(i,j, mom.gene(i,j)); bro.gene(i,j, dad.gene(i,j)); } else{ sis.gene(i,j, dad.gene(i,j)); bro.gene(i,j, mom.gene(i,j)); } count++; } } } else{ int count; int minx = GAMin(mom.width(), dad.width()); int miny = GAMin(mom.height(), dad.height()); count = 0; minx = GAMin(sis.width(), minx); miny = GAMin(sis.height(), miny); for(i=0; i=0; i--){ for(j=sis.height()-1; j>=0; j--){ sis.gene(i,j, ((count%2 == 0) ? mom.gene(i,j) : dad.gene(i,j))); count++; } } } else{ int minx = GAMin(mom.width(), dad.width()); int miny = GAMin(mom.height(), dad.height()); minx = GAMin(sis.width(), minx); miny = GAMin(sis.height(), miny); for(i=minx-1; i>=0; i--) for(j=miny-1; j>=0; j--) sis.gene(i,j, (((i*miny+j)%2 == 0) ? mom.gene(i,j) : dad.gene(i,j))); } nc = 1; } return nc; } galib247/ga/GA2DBinStrGenome.h0100644003643600364360000000765210573535473015146 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- binstr2.h mbwall 19apr95 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved DESCRIPTION: This header defines the interface for the 2D binary string genome, including crossover objects and all the default and built-in operators. ---------------------------------------------------------------------------- */ #ifndef _ga_binstr2_h_ #define _ga_binstr2_h_ #include #include /* ---------------------------------------------------------------------------- 2DBinaryStringGenome ------------------------------------------------------------------------------- ---------------------------------------------------------------------------- */ class GA2DBinaryStringGenome : public GABinaryString, public GAGenome { public: GADefineIdentity("GA2DBinaryStringGenome", GAID::BinaryStringGenome2D); static void UniformInitializer(GAGenome &); static void UnsetInitializer(GAGenome &); static void SetInitializer(GAGenome &); static int FlipMutator(GAGenome &, float); static float BitComparator(const GAGenome&, const GAGenome&); static int UniformCrossover(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*); static int EvenOddCrossover(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*); static int OnePointCrossover(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*); public: GA2DBinaryStringGenome(unsigned int x, unsigned int y, GAGenome::Evaluator f=(GAGenome::Evaluator)0, void * u=(void *)0); GA2DBinaryStringGenome(const GA2DBinaryStringGenome & orig); GA2DBinaryStringGenome& operator=(const GAGenome& arg) {copy(arg); return *this;} GA2DBinaryStringGenome& operator=(const short array []){ for(unsigned int i=0; i #include #include #include #include #include /* ---------------------------------------------------------------------------- 3DArrayGenome ---------------------------------------------------------------------------- */ template const char * GA3DArrayGenome::className() const {return "GA3DArrayGenome";} template int GA3DArrayGenome::classID() const {return GAID::ArrayGenome3D;} template GA3DArrayGenome:: GA3DArrayGenome(unsigned int w, unsigned int h, unsigned int d, GAGenome::Evaluator f, void * u) : GAArray(w*h*d), GAGenome(DEFAULT_3DARRAY_INITIALIZER, DEFAULT_3DARRAY_MUTATOR, DEFAULT_3DARRAY_COMPARATOR) { evaluator(f); userData(u); crossover(DEFAULT_3DARRAY_CROSSOVER); nx=minX=maxX=w; ny=minY=maxY=h; nz=minZ=maxZ=d; } template GA3DArrayGenome:: GA3DArrayGenome(const GA3DArrayGenome & orig) : GAArray(orig.sz), GAGenome(){ GA3DArrayGenome::copy(orig); } template GA3DArrayGenome::~GA3DArrayGenome(){ } template void GA3DArrayGenome::copy(const GAGenome & orig){ if(&orig == this) return; const GA3DArrayGenome* c = DYN_CAST(const GA3DArrayGenome*, &orig); if(c) { GAGenome::copy(*c); GAArray::copy(*c); nx = c->nx; ny = c->ny; nz = c->nz; minX = c->minX; minY = c->minY; minZ = c->minZ; maxX = c->maxX; maxY = c->maxY; maxZ = c->maxZ; } } template GAGenome * GA3DArrayGenome::clone(GAGenome::CloneMethod flag) const { GA3DArrayGenome *cpy = new GA3DArrayGenome(nx,ny,nz); if(flag == CONTENTS){ cpy->copy(*this); } else{ cpy->GAGenome::copy(*this); cpy->minX = minX; cpy->minY = minY; cpy->minZ = minZ; cpy->maxX = maxX; cpy->maxY = maxY; cpy->maxZ = maxZ; } return cpy; } template int GA3DArrayGenome::resize(int w, int h, int d) { if(w == STA_CAST(int,nx) && h == STA_CAST(int,ny) && d == STA_CAST(int,nz)) return this->sz; if(w == GAGenome::ANY_SIZE) w = GARandomInt(minX, maxX); else if(w < 0) w = nx; // do nothing else if(minX == maxX) minX=maxX = w; else{ if(w < STA_CAST(int,minX)) w=minX; if(w > STA_CAST(int,maxX)) w=maxX; } if(h == GAGenome::ANY_SIZE) h = GARandomInt(minY, maxY); else if(h < 0) h = ny; // do nothing else if(minY == maxY) minY=maxY = h; else{ if(h < STA_CAST(int,minY)) h=minY; if(h > STA_CAST(int,maxY)) h=maxY; } if(d == GAGenome::ANY_SIZE) d = GARandomInt(minZ, maxZ); else if(d < 0) d = nz; // do nothing else if(minZ == maxZ) minZ=maxZ = d; else{ if(d < STA_CAST(int,minZ)) d=minZ; if(d > STA_CAST(int,maxZ)) d=maxZ; } if(w < STA_CAST(int,nx) && h < STA_CAST(int,ny)){ int z=GAMin(STA_CAST(int,nz),d); for(int k=0; k::move(k*h*w+j*w,k*ny*nx+j*nx,w); } else if(w < STA_CAST(int,nx)){ int z=GAMin(STA_CAST(int,nz),d); for(int k=0; k::move(k*ny*w+j*w,k*ny*nx+j*nx,w); } else if(h < STA_CAST(int,ny)){ int z=GAMin(STA_CAST(int,nz),d); for(int k=0; k::move(k*h*nx+j*nx,k*ny*nx+j*nx,nx); } GAArray::size(w*h*d); if(w > STA_CAST(int,nx) && h > STA_CAST(int,ny)){ int z=GAMin(STA_CAST(int,nz),d); for(int k=z-1; k>=0; k--) for(int j=ny-1; j>=0; j--) GAArray::move(k*h*w+j*w,k*ny*nx+j*nx,nx); } else if(w > STA_CAST(int,nx)){ int z=GAMin(STA_CAST(int,nz),d); for(int k=z-1; k>=0; k--) for(int j=h-1; j>=0; j--) GAArray::move(k*h*w+j*w,k*h*nx+j*nx,nx); } else if(h > STA_CAST(int,ny)){ int z=GAMin(STA_CAST(int,nz),d); for(int k=z-1; k>=0; k--) for(int j=ny-1; j>=0; j--) GAArray::move(k*h*w+j*w,k*ny*w+j*w,w); } nx = w; ny = h; nz = d; _evaluated = gaFalse; return this->sz; } #ifdef GALIB_USE_STREAMS template int GA3DArrayGenome::read(STD_ISTREAM &) { GAErr(GA_LOC, className(), "read", gaErrOpUndef); return 1; } template int GA3DArrayGenome::write(STD_OSTREAM & os) const { for(unsigned int k=0; k int GA3DArrayGenome::resizeBehaviour(GAGenome::Dimension which) const { int val = 0; if(which == WIDTH) { if(maxX == minX) val = FIXED_SIZE; else val = maxX; } else if(which == HEIGHT) { if(maxY == minY) val = FIXED_SIZE; else val = maxY; } else if(which == DEPTH) { if(maxZ == minZ) val = FIXED_SIZE; else val = maxZ; } return val; } template int GA3DArrayGenome:: resizeBehaviour(GAGenome::Dimension which, unsigned int lower, unsigned int upper) { if(upper < lower){ GAErr(GA_LOC, className(), "resizeBehaviour", gaErrBadResizeBehaviour); return resizeBehaviour(which); } switch(which){ case WIDTH: minX = lower; maxX = upper; if(nx > upper) GA3DArrayGenome::resize(upper,ny,nz); if(nx < lower) GA3DArrayGenome::resize(lower,ny,nz); break; case HEIGHT: minY = lower; maxY = upper; if(ny > upper) GA3DArrayGenome::resize(nx,upper,nz); if(ny < lower) GA3DArrayGenome::resize(nx,lower,nz); break; case DEPTH: minZ = lower; maxZ = upper; if(nz > upper) GA3DArrayGenome::resize(nx,ny,upper); if(nz < lower) GA3DArrayGenome::resize(nx,ny,lower); break; default: break; } return resizeBehaviour(which); } template void GA3DArrayGenome:: copy(const GA3DArrayGenome & orig, unsigned int r, unsigned int s, unsigned int t, unsigned int x, unsigned int y, unsigned int z, unsigned int w, unsigned int h, unsigned int d) { if(w == 0 || x >= orig.nx || r >= nx || h == 0 || y >= orig.ny || s >= ny || d == 0 || z >= orig.nz || t >= nz) return; if(x + w > orig.nx) w = orig.nx - x; if(y + h > orig.ny) h = orig.ny - y; if(z + d > orig.nz) d = orig.nz - z; if(r + w > nx) w = nx - r; if(s + h > ny) h = ny - s; if(t + d > nz) d = nz - t; for(unsigned int k=0; k::copy(orig, (t+k)*ny*nx + (s+j)*nx + r, (z+k)*orig.ny*orig.nx + (y+j)*orig.nx + x, w); _evaluated = gaFalse; } template int GA3DArrayGenome::equal(const GAGenome & c) const { if(this == &c) return 1; GA3DArrayGenome & b = (GA3DArrayGenome &)c; if(nx != b.nx || ny != b.ny || nz != b.nz) return 0; int val=0; for(unsigned int k=0; k::equal(b,k*ny*nx,k*ny*nx,nx) ? 0 : 1; return(val ? 0 : 1); } /* ---------------------------------------------------------------------------- 3DArrayAlleleGenome ---------------------------------------------------------------------------- */ template const char * GA3DArrayAlleleGenome::className() const {return "GA3DArrayAlleleGenome";} template int GA3DArrayAlleleGenome::classID() const {return GAID::ArrayAlleleGenome3D;} template GA3DArrayAlleleGenome:: GA3DArrayAlleleGenome(unsigned int w, unsigned int h, unsigned int d, const GAAlleleSet & s, GAGenome::Evaluator f, void * u) : GA3DArrayGenome(w,h,d,f,u) { naset = 1; aset = new GAAlleleSet[1]; aset[0] = s; initializer(GA3DArrayAlleleGenome::DEFAULT_3DARRAY_ALLELE_INITIALIZER); mutator(GA3DArrayAlleleGenome::DEFAULT_3DARRAY_ALLELE_MUTATOR); comparator(GA3DArrayAlleleGenome::DEFAULT_3DARRAY_ALLELE_COMPARATOR); crossover(GA3DArrayAlleleGenome::DEFAULT_3DARRAY_ALLELE_CROSSOVER); } template GA3DArrayAlleleGenome:: GA3DArrayAlleleGenome(unsigned int w, unsigned int h, unsigned int d, const GAAlleleSetArray & sa, GAGenome::Evaluator f, void * u) : GA3DArrayGenome(w,h,d, f, u) { naset = sa.size(); aset = new GAAlleleSet[naset]; for(int i=0; i::DEFAULT_3DARRAY_ALLELE_INITIALIZER); mutator(GA3DArrayAlleleGenome::DEFAULT_3DARRAY_ALLELE_MUTATOR); comparator(GA3DArrayAlleleGenome::DEFAULT_3DARRAY_ALLELE_COMPARATOR); crossover(GA3DArrayAlleleGenome::DEFAULT_3DARRAY_ALLELE_CROSSOVER); } template GA3DArrayAlleleGenome:: GA3DArrayAlleleGenome(const GA3DArrayAlleleGenome & orig) : GA3DArrayGenome(orig.nx, orig.ny, orig.nz) { naset = 0; aset = (GAAlleleSet*)0; GA3DArrayAlleleGenome::copy(orig); } template GA3DArrayAlleleGenome::~GA3DArrayAlleleGenome(){ delete [] aset; } template GAGenome * GA3DArrayAlleleGenome::clone(GAGenome::CloneMethod) const { return new GA3DArrayAlleleGenome(*this); } template void GA3DArrayAlleleGenome::copy(const GAGenome& orig){ if(&orig == this) return; const GA3DArrayAlleleGenome* c = DYN_CAST(const GA3DArrayAlleleGenome*, &orig); if(c) { GA3DArrayGenome::copy(*c); if(naset != c->naset){ delete [] aset; naset = c->naset; aset = new GAAlleleSet[c->naset]; } for(int i=0; iaset[i]); } } template int GA3DArrayAlleleGenome::resize(int w, int h, int d){ unsigned int oldx = this->nx; unsigned int oldy = this->ny; unsigned int oldz = this->nz; GA3DArrayGenome::resize(w,h,d); // set new elements to proper randomly selected values if(this->nx > oldx && this->ny > oldy){ int z=GAMin(oldz,this->nz); for(int k=z-1; k>=0; k--){ int j; for(j=oldy-1; j>=0; j--) for(unsigned int i=oldx; inx; i++) this->a[k * this->ny * this->nx + j * this->nx + i] = aset[(k*this->ny*this->nx+j*this->nx+i) % naset].allele(); for(j=oldy; jny); j++) for(unsigned int i=0; inx; i++) this->a[k * this->ny * this->nx + j * this->nx + i] = aset[(k * this->ny * this->nx + j * this->nx + i) % naset].allele(); } } else if(this->nx > oldx){ int z=GAMin(oldz,this->nz); for(int k=z-1; k>=0; k--) for(int j=this->ny-1; j>=0; j--) for(unsigned int i=oldx; inx; i++) this->a[k*this->ny*this->nx+j*this->nx+i] = aset[(k*this->ny*this->nx+j*this->nx+i) % naset].allele(); } else if(this->ny > oldy){ int z=GAMin(oldz,this->nz); for(int k=z-1; k>=0; k--) for(unsigned int j=oldy; jny; j++) for(unsigned int i=0; inx; i++) this->a[k*this->ny*this->nx+j*this->nx+i] = aset[(k*this->ny*this->nx+j*this->nx+i) % naset].allele(); } if(this->nz > oldz){ // change in depth is always new elements for(unsigned int i=this->nx*this->ny*oldz; inx*this->ny*this->nz; i++) this->a[i] = aset[i % naset].allele(); } return this->sz; } #ifdef GALIB_USE_STREAMS template int GA3DArrayAlleleGenome::read(STD_ISTREAM& is){ return GA3DArrayGenome::read(is); } template int GA3DArrayAlleleGenome::write(STD_OSTREAM& os) const { return GA3DArrayGenome::write(os); } #endif template int GA3DArrayAlleleGenome::equal(const GAGenome & c) const { return GA3DArrayGenome::equal(c); } /* ---------------------------------------------------------------------------- Operator definitions ---------------------------------------------------------------------------- */ // this does not handle genomes with multiple allele sets! template void GA3DArrayAlleleGenome::UniformInitializer(GAGenome & c) { GA3DArrayAlleleGenome &child= DYN_CAST(GA3DArrayAlleleGenome &, c); child.resize(GAGenome::ANY_SIZE,GAGenome::ANY_SIZE,GAGenome::ANY_SIZE); for(int i=child.width()-1; i>=0; i--) for(int j=child.height()-1; j>=0; j--) for(int k=child.depth()-1; k>=0; k--) child.gene(i, j, k, child.alleleset().allele()); } template int GA3DArrayAlleleGenome::FlipMutator(GAGenome & c, float pmut) { GA3DArrayAlleleGenome &child= DYN_CAST(GA3DArrayAlleleGenome &, c); register int n, m, d, i, j, k; if(pmut <= 0.0) return(0); float nMut = pmut * STA_CAST(float,child.size()); if(nMut < 1.0){ // we have to do a flip test on each bit nMut = 0; for(i=child.width()-1; i>=0; i--){ for(j=child.height()-1; j>=0; j--){ for(k=child.depth()-1; k>=0; k--){ if(GAFlipCoin(pmut)){ child.gene(i, j, k, child.alleleset().allele()); nMut++; } } } } } else{ // only flip the number of bits we need to flip for(n=0; n int GA3DArrayGenome::SwapMutator(GAGenome & c, float pmut) { GA3DArrayGenome &child=DYN_CAST(GA3DArrayGenome&, c); register int n, i; if(pmut <= 0.0) return(0); float nMut = pmut * STA_CAST(float,child.size()); int size = child.size()-1; if(nMut < 1.0){ // we have to do a flip test on each bit nMut = 0; for(i=size; i>=0; i--){ if(GAFlipCoin(pmut)){ child.GAArray::swap(i, GARandomInt(0, size)); nMut++; } } } else{ // only flip the number of bits we need to flip for(n=0; n::swap(GARandomInt(0, size), GARandomInt(0, size)); } return(STA_CAST(int,nMut)); } template float GA3DArrayGenome:: ElementComparator(const GAGenome& a, const GAGenome& b) { const GA3DArrayGenome& sis= DYN_CAST(const GA3DArrayGenome&, a); const GA3DArrayGenome& bro= DYN_CAST(const GA3DArrayGenome&, b); if(sis.size() != bro.size()) return -1; if(sis.size() == 0) return 0; float count = 0.0; for(int i=sis.width()-1; i>=0; i--) for(int j=sis.height()-1; j>=0; j--) for(int k=sis.depth()-1; k>=0; k--) count += ((sis.gene(i,j,k) == bro.gene(i,j,k)) ? 0 : 1); return count/sis.size(); } // Make sure our bitmask is big enough, generate a mask, then use it to // extract the information from each parent to stuff the two children. // We don't deallocate any space for the masks under the assumption that we'll // have to use them again in the future. // For now we'll implement this only for fixed length genomes. If you use // this crossover method on genomes of different sizes it might break! template int GA3DArrayGenome:: UniformCrossover(const GAGenome& p1, const GAGenome& p2, GAGenome* c1, GAGenome* c2){ const GA3DArrayGenome &mom=DYN_CAST(const GA3DArrayGenome &, p1); const GA3DArrayGenome &dad=DYN_CAST(const GA3DArrayGenome &, p2); int nc=0; int i,j,k; if(c1 && c2){ GA3DArrayGenome &sis=DYN_CAST(GA3DArrayGenome &, *c1); GA3DArrayGenome &bro=DYN_CAST(GA3DArrayGenome &, *c2); if(sis.width() == bro.width() && sis.height() == bro.height() && sis.depth() == bro.depth() && mom.width() == dad.width() && mom.height() == dad.height() && mom.depth() == dad.depth() && sis.width() == mom.width() && sis.height() == mom.height() && sis.depth() == mom.depth()){ for(i=sis.width()-1; i>=0; i--){ for(j=sis.height()-1; j>=0; j--){ for(k=sis.depth()-1; k>=0; k--){ if(GARandomBit()){ sis.gene(i,j,k, mom.gene(i,j,k)); bro.gene(i,j,k, dad.gene(i,j,k)); } else{ sis.gene(i,j,k, dad.gene(i,j,k)); bro.gene(i,j,k, mom.gene(i,j,k)); } } } } } else{ GAMask mask; int startx, starty, startz; int maxx = (sis.width() > bro.width()) ? sis.width() : bro.width(); int minx = (mom.width() < dad.width()) ? mom.width() : dad.width(); int maxy = (sis.height() > bro.height()) ? sis.height() : bro.height(); int miny = (mom.height() < dad.height()) ? mom.height() : dad.height(); int maxz = (sis.depth() > bro.depth()) ? sis.depth() : bro.depth(); int minz = (mom.depth() < dad.depth()) ? mom.depth() : dad.depth(); mask.size(maxx*maxy*maxz); for(i=0; i=0; i--) for(j=starty-1; j>=0; j--) for(k=startz-1; k>=0; k--) sis.gene(i,j,k, (mask[i*starty*startz+j*startz+k] ? mom.gene(i,j,k) : dad.gene(i,j,k))); startx = (bro.width() < minx) ? bro.width() : minx; starty = (bro.height() < miny) ? bro.height() : miny; startz = (bro.depth() < minz) ? bro.depth() : minz; for(i=startx-1; i>=0; i--) for(j=starty-1; j>=0; j--) for(k=startz-1; k>=0; k--) bro.gene(i,j,k, (mask[i*starty*startz+j*startz+k] ? dad.gene(i,j,k) : mom.gene(i,j,k))); } nc = 2; } else if(c1){ GA3DArrayGenome &sis=DYN_CAST(GA3DArrayGenome &, *c1); if(mom.width() == dad.width() && mom.height() == dad.height() && mom.depth() == dad.depth() && sis.width() == mom.width() && sis.height() == mom.height() && sis.depth() == mom.depth()){ for(i=sis.width()-1; i>=0; i--) for(j=sis.height()-1; j>=0; j--) for(k=sis.depth()-1; k>=0; k--) sis.gene(i,j,k, (GARandomBit() ? mom.gene(i,j,k):dad.gene(i,j,k))); } else{ int minx = (mom.width() < dad.width()) ? mom.width() : dad.width(); int miny = (mom.height() < dad.height()) ? mom.height() : dad.height(); int minz = (mom.depth() < dad.depth()) ? mom.depth() : dad.depth(); minx = (sis.width() < minx) ? sis.width() : minx; miny = (sis.height() < miny) ? sis.height() : miny; minz = (sis.depth() < minz) ? sis.depth() : minz; for(i=minx-1; i>=0; i--) for(j=miny-1; j>=0; j--) for(k=minz-1; k>=0; k--) sis.gene(i,j,k, (GARandomBit() ? mom.gene(i,j,k):dad.gene(i,j,k))); } nc = 1; } return nc; } // For even crossover we take the even bits from the mother (for the daughter) // and the odd bits from the father. Just the opposite for the son. // This is designed only for genomes that are the same length. If the child // is not the same length as the parent, or if the children are not the same // size, we don't do the crossover. // In the interest of speed we do not do any checks for size. Do not use // this crossover method when the parents and children may be different sizes. // It might break! template int GA3DArrayGenome:: EvenOddCrossover(const GAGenome& p1, const GAGenome& p2, GAGenome* c1, GAGenome* c2){ const GA3DArrayGenome &mom=DYN_CAST(const GA3DArrayGenome &, p1); const GA3DArrayGenome &dad=DYN_CAST(const GA3DArrayGenome &, p2); int nc=0; int i,j,k; if(c1 && c2){ GA3DArrayGenome &sis=DYN_CAST(GA3DArrayGenome &, *c1); GA3DArrayGenome &bro=DYN_CAST(GA3DArrayGenome &, *c2); if(sis.width() == bro.width() && sis.height() == bro.height() && sis.depth() == bro.depth() && mom.width() == dad.width() && mom.height() == dad.height() && mom.depth() == dad.depth() && sis.width() == mom.width() && sis.height() == mom.height() && sis.depth() == mom.depth()){ int count=0; for(i=sis.width()-1; i>=0; i--){ for(j=sis.height()-1; j>=0; j--){ for(k=sis.depth()-1; k>=0; k--){ sis.gene(i,j,k,((count%2 == 0) ? mom.gene(i,j,k):dad.gene(i,j,k))); bro.gene(i,j,k,((count%2 == 0) ? dad.gene(i,j,k):mom.gene(i,j,k))); count++; } } } } else{ int startx, starty, startz; int maxx = (sis.width() > bro.width()) ? sis.width() : bro.width(); int minx = (mom.width() < dad.width()) ? mom.width() : dad.width(); int maxy = (sis.height() > bro.height()) ? sis.height() : bro.height(); int miny = (mom.height() < dad.height()) ? mom.height() : dad.height(); int maxz = (sis.depth() > bro.depth()) ? sis.depth() : bro.depth(); int minz = (mom.depth() < dad.depth()) ? mom.depth() : dad.depth(); startx = (sis.width() < minx) ? sis.width() : minx; starty = (sis.height() < miny) ? sis.height() : miny; startz = (sis.depth() < minz) ? sis.depth() : minz; for(i=startx-1; i>=0; i--) for(j=starty-1; j>=0; j--) for(k=startz-1; k>=0; k--) sis.gene(i,j,k, (((i*starty*startz+j*startz+k)%2 == 0) ? mom.gene(i,j,k) : dad.gene(i,j,k))); startx = (bro.width() < minx) ? bro.width() : minx; starty = (bro.height() < miny) ? bro.height() : miny; startz = (bro.depth() < minz) ? bro.depth() : minz; for(i=startx-1; i>=0; i--) for(j=starty-1; j>=0; j--) for(k=startz-1; k>=0; k--) bro.gene(i,j,k, (((i*starty*startz+j*startz+k)%2 == 0) ? dad.gene(i,j,k) : mom.gene(i,j,k))); } nc = 2; } else if(c1){ GA3DArrayGenome &sis=DYN_CAST(GA3DArrayGenome &, *c1); if(mom.width() == dad.width() && mom.height() == dad.height() && mom.depth() == dad.depth() && sis.width() == mom.width() && sis.height() == mom.height() && sis.depth() == mom.depth()){ int count=0; for(i=sis.width()-1; i>=0; i--){ for(j=sis.height()-1; j>=0; j--){ for(k=sis.depth()-1; k>=0; k--){ sis.gene(i,j,k,((count%2 == 0) ? mom.gene(i,j,k):dad.gene(i,j,k))); count++; } } } } else{ int minx = (mom.width() < dad.width()) ? mom.width() : dad.width(); int miny = (mom.height() < dad.height()) ? mom.height() : dad.height(); int minz = (mom.depth() < dad.depth()) ? mom.depth() : dad.depth(); minx = (sis.width() < minx) ? sis.width() : minx; miny = (sis.height() < miny) ? sis.height() : miny; minz = (sis.depth() < minz) ? sis.depth() : minz; for(i=minx-1; i>=0; i--) for(j=miny-1; j>=0; j--) for(k=minz-1; k>=0; k--) sis.gene(i,j, (((i*miny*minz+j*minz+k)%2 == 0) ? mom.gene(i,j,k) : dad.gene(i,j,k))); } nc = 1; } return nc; } // Pick a single point in the 3D block and grab alternating quadrants for each // child. If the children are resizable, this crossover does clipping. template int GA3DArrayGenome:: OnePointCrossover(const GAGenome& p1, const GAGenome& p2, GAGenome* c1, GAGenome* c2){ const GA3DArrayGenome &mom=DYN_CAST(const GA3DArrayGenome &, p1); const GA3DArrayGenome &dad=DYN_CAST(const GA3DArrayGenome &, p2); int nc=0; unsigned int momsitex, momlenx, momsitey, momleny, momsitez, momlenz; unsigned int dadsitex, dadlenx, dadsitey, dadleny, dadsitez, dadlenz; unsigned int sitex, lenx, sitey, leny, sitez, lenz; if(c1 && c2){ GA3DArrayGenome &sis=DYN_CAST(GA3DArrayGenome &, *c1); GA3DArrayGenome &bro=DYN_CAST(GA3DArrayGenome &, *c2); if(sis.resizeBehaviour(GAGenome::WIDTH) == GAGenome::FIXED_SIZE && bro.resizeBehaviour(GAGenome::WIDTH) == GAGenome::FIXED_SIZE){ if(mom.width() != dad.width() || sis.width() != bro.width() || sis.width() != mom.width()){ GAErr(GA_LOC, mom.className(), "one-point cross", gaErrSameLengthReqd); return nc; } sitex = momsitex = dadsitex = GARandomInt(0, mom.width()); lenx = momlenx = dadlenx = mom.width() - momsitex; } else if(sis.resizeBehaviour(GAGenome::WIDTH) == GAGenome::FIXED_SIZE || bro.resizeBehaviour(GAGenome::WIDTH) == GAGenome::FIXED_SIZE){ GAErr(GA_LOC, mom.className(), "one-point cross", gaErrSameBehavReqd); return nc; } else{ momsitex = GARandomInt(0, mom.width()); dadsitex = GARandomInt(0, dad.width()); momlenx = mom.width() - momsitex; dadlenx = dad.width() - dadsitex; sitex = GAMin(momsitex, dadsitex); lenx = GAMin(momlenx, dadlenx); } if(sis.resizeBehaviour(GAGenome::HEIGHT) == GAGenome::FIXED_SIZE && bro.resizeBehaviour(GAGenome::HEIGHT) == GAGenome::FIXED_SIZE){ if(mom.height() != dad.height() || sis.height() != bro.height() || sis.height() != mom.height()){ GAErr(GA_LOC, mom.className(), "one-point cross", gaErrSameLengthReqd); return nc; } sitey = momsitey = dadsitey = GARandomInt(0, mom.height()); leny = momleny = dadleny = mom.height() - momsitey; } else if(sis.resizeBehaviour(GAGenome::HEIGHT) == GAGenome::FIXED_SIZE || bro.resizeBehaviour(GAGenome::HEIGHT) == GAGenome::FIXED_SIZE){ GAErr(GA_LOC, mom.className(), "one-point cross", gaErrSameBehavReqd); return nc; } else{ momsitey = GARandomInt(0, mom.height()); dadsitey = GARandomInt(0, dad.height()); momleny = mom.height() - momsitey; dadleny = dad.height() - dadsitey; sitey = GAMin(momsitey, dadsitey); leny = GAMin(momleny, dadleny); } if(sis.resizeBehaviour(GAGenome::DEPTH) == GAGenome::FIXED_SIZE && bro.resizeBehaviour(GAGenome::DEPTH) == GAGenome::FIXED_SIZE){ if(mom.depth() != dad.depth() || sis.depth() != bro.depth() || sis.depth() != mom.depth()){ GAErr(GA_LOC, mom.className(), "one-point cross", gaErrSameLengthReqd); return nc; } sitez = momsitez = dadsitez = GARandomInt(0, mom.depth()); lenz = momlenz = dadlenz = mom.depth() - momsitez; } else if(sis.resizeBehaviour(GAGenome::DEPTH) == GAGenome::FIXED_SIZE || bro.resizeBehaviour(GAGenome::DEPTH) == GAGenome::FIXED_SIZE){ GAErr(GA_LOC, mom.className(), "one-point cross", gaErrSameBehavReqd); return nc; } else{ momsitez = GARandomInt(0, mom.depth()); dadsitez = GARandomInt(0, dad.depth()); momlenz = mom.depth() - momsitez; dadlenz = dad.depth() - dadsitez; sitez = GAMin(momsitez, dadsitez); lenz = GAMin(momlenz, dadlenz); } sis.resize(sitex+lenx, sitey+leny, sitez+lenz); bro.resize(sitex+lenx, sitey+leny, sitez+lenz); sis.copy(mom, 0, 0, 0, momsitex-sitex, momsitey-sitey, momsitez-sitez, sitex, sitey, sitez); sis.copy(dad, sitex, 0, 0, dadsitex, dadsitey-sitey, dadsitez-sitez, lenx, sitey, sitez); sis.copy(dad, 0, sitey, 0, dadsitex-sitex, dadsitey, dadsitez-sitez, sitex, leny, sitez); sis.copy(mom, sitex, sitey, 0, momsitex, momsitey, momsitez-sitez, lenx, leny, sitez); sis.copy(dad, 0, 0, sitez, dadsitex-sitex, dadsitey-sitey, dadsitez, sitex, sitey, lenz); sis.copy(mom, sitex, 0, sitez, momsitex, momsitey-sitey, momsitez, lenx, sitey, lenz); sis.copy(mom, 0, sitey, sitez, momsitex-sitex, momsitey, momsitez, sitex, leny, lenz); sis.copy(dad, sitex, sitey, sitez, dadsitex, dadsitey, dadsitez, lenx, leny, lenz); bro.copy(dad, 0, 0, 0, dadsitex-sitex, dadsitey-sitey, dadsitez-sitez, sitex, sitey, sitez); bro.copy(mom, sitex, 0, 0, momsitex, momsitey-sitey, momsitez-sitez, lenx, sitey, sitez); bro.copy(mom, 0, sitey, 0, momsitex-sitex, momsitey, momsitez-sitez, sitex, leny, sitez); bro.copy(dad, sitex, sitey, 0, dadsitex, dadsitey, dadsitez-sitez, lenx, leny, sitez); bro.copy(mom, 0, 0, sitez, momsitex-sitex, momsitey-sitey, momsitez, sitex, sitey, lenz); bro.copy(dad, sitex, 0, sitez, dadsitex, dadsitey-sitey, dadsitez, lenx, sitey, lenz); bro.copy(dad, 0, sitey, sitez, dadsitex-sitex, dadsitey, dadsitez, sitex, leny, lenz); bro.copy(mom, sitex, sitey, sitez, momsitex, momsitey, momsitez, lenx, leny, lenz); nc = 2; } else if(c1){ GA3DArrayGenome &sis=DYN_CAST(GA3DArrayGenome &, *c1); if(sis.resizeBehaviour(GAGenome::WIDTH) == GAGenome::FIXED_SIZE){ if(mom.width() != dad.width() || sis.width() != mom.width()){ GAErr(GA_LOC, mom.className(), "one-point cross", gaErrSameLengthReqd); return nc; } sitex = momsitex = dadsitex = GARandomInt(0, mom.width()); lenx = momlenx = dadlenx = mom.width() - momsitex; } else{ momsitex = GARandomInt(0, mom.width()); dadsitex = GARandomInt(0, dad.width()); momlenx = mom.width() - momsitex; dadlenx = dad.width() - dadsitex; sitex = GAMin(momsitex, dadsitex); lenx = GAMin(momlenx, dadlenx); } if(sis.resizeBehaviour(GAGenome::HEIGHT) == GAGenome::FIXED_SIZE){ if(mom.height() != dad.height() || sis.height() != mom.height()){ GAErr(GA_LOC, mom.className(), "one-point cross", gaErrSameLengthReqd); return nc; } sitey = momsitey = dadsitey = GARandomInt(0, mom.height()); leny = momleny = dadleny = mom.height() - momsitey; } else{ momsitey = GARandomInt(0, mom.height()); dadsitey = GARandomInt(0, dad.height()); momleny = mom.height() - momsitey; dadleny = dad.height() - dadsitey; sitey = GAMin(momsitey, dadsitey); leny = GAMin(momleny, dadleny); } if(sis.resizeBehaviour(GAGenome::DEPTH) == GAGenome::FIXED_SIZE){ if(mom.depth() != dad.depth() || sis.depth() != mom.depth()){ GAErr(GA_LOC, mom.className(), "one-point cross", gaErrSameLengthReqd); return nc; } sitez = momsitez = dadsitez = GARandomInt(0, mom.depth()); lenz = momlenz = dadlenz = mom.depth() - momsitez; } else{ momsitez = GARandomInt(0, mom.depth()); dadsitez = GARandomInt(0, dad.depth()); momlenz = mom.depth() - momsitez; dadlenz = dad.depth() - dadsitez; sitez = GAMin(momsitez, dadsitez); lenz = GAMin(momlenz, dadlenz); } sis.resize(sitex+lenx, sitey+leny, sitez+lenz); if(GARandomBit()){ sis.copy(mom, 0, 0, 0, momsitex-sitex, momsitey-sitey, momsitez-sitez, sitex, sitey, sitez); sis.copy(dad, sitex, 0, 0, dadsitex, dadsitey-sitey, dadsitez-sitez, lenx, sitey, sitez); sis.copy(dad, 0, sitey, 0, dadsitex-sitex, dadsitey, dadsitez-sitez, sitex, leny, sitez); sis.copy(mom, sitex, sitey, 0, momsitex, momsitey, momsitez-sitez, lenx, leny, sitez); sis.copy(dad, 0, 0, sitez, dadsitex-sitex, dadsitey-sitey, dadsitez, sitex, sitey, lenz); sis.copy(mom, sitex, 0, sitez, momsitex, momsitey-sitey, momsitez, lenx, sitey, lenz); sis.copy(mom, 0, sitey, sitez, momsitex-sitex, momsitey, momsitez, sitex, leny, lenz); sis.copy(dad, sitex, sitey, sitez, dadsitex, dadsitey, dadsitez, lenx, leny, lenz); } else{ sis.copy(dad, 0, 0, 0, dadsitex-sitex, dadsitey-sitey, dadsitez-sitez, sitex, sitey, sitez); sis.copy(mom, sitex, 0, 0, momsitex, momsitey-sitey, momsitez-sitez, lenx, sitey, sitez); sis.copy(mom, 0, sitey, 0, momsitex-sitex, momsitey, momsitez-sitez, sitex, leny, sitez); sis.copy(dad, sitex, sitey, 0, dadsitex, dadsitey, dadsitez-sitez, lenx, leny, sitez); sis.copy(mom, 0, 0, sitez, momsitex-sitex, momsitey-sitey, momsitez, sitex, sitey, lenz); sis.copy(dad, sitex, 0, sitez, dadsitex, dadsitey-sitey, dadsitez, lenx, sitey, lenz); sis.copy(dad, 0, sitey, sitez, dadsitex-sitex, dadsitey, dadsitez, sitex, leny, lenz); sis.copy(mom, sitex, sitey, sitez, momsitex, momsitey, momsitez, lenx, leny, lenz); } nc = 1; } return nc; } #endif galib247/ga/GA3DArrayGenome.h0100644003643600364360000001212010573535474015007 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- array3.h mbwall 25feb95 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved DESCRIPTION: This header defines the interface for the 3D array genome. See comments in 1D array file. ---------------------------------------------------------------------------- */ #ifndef _ga_array3_h_ #define _ga_array3_h_ #include #include #include /* ---------------------------------------------------------------------------- 3DArrayGenome ---------------------------------------------------------------------------- */ template class GA3DArrayGenome : public GAArray, public GAGenome { public: GADeclareIdentity(); static int SwapMutator(GAGenome&, float); static float ElementComparator(const GAGenome&, const GAGenome&); static int UniformCrossover(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*); static int EvenOddCrossover(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*); static int OnePointCrossover(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*); public: GA3DArrayGenome(unsigned int x, unsigned int y, unsigned int z, GAGenome::Evaluator f=(GAGenome::Evaluator)0, void * u=(void *)0); GA3DArrayGenome(const GA3DArrayGenome & orig); GA3DArrayGenome& operator=(const GAGenome& orig) {copy(orig); return *this;} GA3DArrayGenome& operator=(const T array []){ for(unsigned int i=0; ia[z*ny*nx + y*nx + x]; } T & gene(unsigned int x, unsigned int y, unsigned int z, const T & value){ if(this->a[z*ny*nx + y*nx + x] != value){ _evaluated = gaFalse; this->a[z*ny*nx + y*nx + x] = value; } return this->a[z*ny*nx + y*nx + x]; } int width() const {return nx;} int width(int w){resize(w, ny, nz); return nx;} int height() const {return ny;} int height(int h){resize(nx, h, nz); return ny;} int depth() const {return nz;} int depth(int d){resize(nx, ny, d); return nz;} virtual int resize(int x, int y, int z); int resizeBehaviour(Dimension which) const ; int resizeBehaviour(Dimension which, unsigned int lower, unsigned int upper); int resizeBehaviour(unsigned int lowerX, unsigned int upperX, unsigned int lowerY, unsigned int upperY, unsigned int lowerZ, unsigned int upperZ){ return(resizeBehaviour(WIDTH, lowerX, upperX) * resizeBehaviour(HEIGHT, lowerY, upperY) * resizeBehaviour(DEPTH, lowerZ, upperZ)); } void copy(const GA3DArrayGenome &, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int); void swap(unsigned int a, unsigned int b, unsigned int c, unsigned int d, unsigned int e, unsigned int f){ GAArray::swap(c*ny*nx+b*nx+a, f*ny*nx+e*nx+d); _evaluated = gaFalse; } protected: unsigned int nx, ny, nz, minX, minY, minZ, maxX, maxY, maxZ; }; /* ---------------------------------------------------------------------------- 3DArrayAlleleGenome ---------------------------------------------------------------------------- */ template class GA3DArrayAlleleGenome : public GA3DArrayGenome { public: GADeclareIdentity(); static void UniformInitializer(GAGenome&); static int FlipMutator(GAGenome&, float); public: GA3DArrayAlleleGenome(unsigned int x, unsigned int y, unsigned int z, const GAAlleleSet & a, GAGenome::Evaluator f=(GAGenome::Evaluator)0, void * u=(void *)0); GA3DArrayAlleleGenome(unsigned int x, unsigned int y, unsigned int z, const GAAlleleSetArray & a, GAGenome::Evaluator f=(GAGenome::Evaluator)0, void * u=(void *)0); GA3DArrayAlleleGenome(const GA3DArrayAlleleGenome & orig); GA3DArrayAlleleGenome& operator=(const GAGenome& orig) {copy(orig); return *this;} GA3DArrayAlleleGenome& operator=(const T array []) {GA3DArrayGenome::operator=(array); return *this;} virtual ~GA3DArrayAlleleGenome(); virtual GAGenome * clone(GAGenome::CloneMethod flag=GAGenome::CONTENTS) const; virtual void copy(const GAGenome &); #ifdef GALIB_USE_STREAMS virtual int read(STD_ISTREAM & is); virtual int write (STD_OSTREAM & os) const; #endif virtual int equal(const GAGenome & c) const ; virtual int resize(int x, int y, int z); const GAAlleleSet& alleleset(unsigned int i=0) const {return aset[i%naset];} protected: int naset; GAAlleleSet * aset; }; #ifdef GALIB_USE_BORLAND_INST #include #endif #endif galib247/ga/GA3DBinStrGenome.C0100644003643600364360000007530210573535474015100 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- binstr3.C mbwall 19apr95 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved DESCRIPTION: Source file for the 3D binary string genome. See the 1D genome for comments. ---------------------------------------------------------------------------- */ #include #include #include #include #include #include #include #include /* ---------------------------------------------------------------------------- Genome class definition ---------------------------------------------------------------------------- */ GA3DBinaryStringGenome:: GA3DBinaryStringGenome(unsigned int width, unsigned int height, unsigned int depth, GAGenome::Evaluator f, void * u) : GABinaryString(width*height*depth), GAGenome(DEFAULT_3DBINSTR_INITIALIZER, DEFAULT_3DBINSTR_MUTATOR, DEFAULT_3DBINSTR_COMPARATOR) { evaluator(f); userData(u); crossover(DEFAULT_3DBINSTR_CROSSOVER); nx=minX=maxX=0; ny=minY=maxY=0; nz=minZ=maxZ=0; resize(width, height, depth); } GA3DBinaryStringGenome:: GA3DBinaryStringGenome(const GA3DBinaryStringGenome & orig) : GABinaryString(orig.GABinaryString::size()), GAGenome() { nx=minX=maxX=0; ny=minY=maxY=0; nz=minZ=maxZ=0; GA3DBinaryStringGenome::copy(orig); } GA3DBinaryStringGenome::~GA3DBinaryStringGenome() { } GAGenome * GA3DBinaryStringGenome::clone(GAGenome::CloneMethod flag) const { GA3DBinaryStringGenome *cpy = new GA3DBinaryStringGenome(nx,ny,nz); if(flag == CONTENTS){ cpy->copy(*this); } else{ cpy->GAGenome::copy(*this); cpy->minX = minX; cpy->minY = minY; cpy->minZ = minZ; cpy->maxX = maxX; cpy->maxY = maxY; cpy->maxZ = maxZ; } return cpy; } void GA3DBinaryStringGenome::copy(const GAGenome & orig) { if(&orig == this) return; const GA3DBinaryStringGenome* c = DYN_CAST(const GA3DBinaryStringGenome*, &orig); if(c) { GAGenome::copy(*c); GABinaryString::copy(*c); nx = c->nx; ny = c->ny; nz = c->nz; minX = c->minX; minY = c->minY; minZ = c->minZ; maxX = c->maxX; maxY = c->maxY; maxZ = c->maxZ; } } int GA3DBinaryStringGenome::resize(int w, int h, int d) { if(w == STA_CAST(int,nx) && h == STA_CAST(int,ny) && d == STA_CAST(int,nz)) return sz; if(w == GAGenome::ANY_SIZE) w = GARandomInt(minX, maxX); else if(w < 0) w = nx; // do nothing else if(minX == maxX) minX=maxX = w; else{ if(w < STA_CAST(int,minX)) w=minX; if(w > STA_CAST(int,maxX)) w=maxX; } if(h == GAGenome::ANY_SIZE) h = GARandomInt(minY, maxY); else if(h < 0) h = ny; // do nothing else if(minY == maxY) minY=maxY = h; else{ if(h < STA_CAST(int,minY)) h=minY; if(h > STA_CAST(int,maxY)) h=maxY; } if(d == GAGenome::ANY_SIZE) d = GARandomInt(minZ, maxZ); else if(d < 0) d = nz; // do nothing else if(minZ == maxZ) minZ=maxZ = d; else{ if(d < STA_CAST(int,minZ)) d=minZ; if(d > STA_CAST(int,maxZ)) d=maxZ; } if(w < STA_CAST(int,nx) && h < STA_CAST(int,ny)){ int z=GAMin(STA_CAST(int,nz),d); for(int k=0; k STA_CAST(int,nx) && h > STA_CAST(int,ny)){ // adjust the existing bits int z=GAMin(STA_CAST(int,nz),d); for(int k=z-1; k>=0; k--){ int j; for(j=ny-1; j>=0; j--){ GABinaryString::move(k*h*w+j*w,k*ny*nx+j*nx,nx); for(int i=nx; i STA_CAST(int,nx)){ int z=GAMin(STA_CAST(int,nz),d); for(int k=z-1; k>=0; k--){ for(int j=h-1; j>=0; j--){ GABinaryString::move(k*h*w+j*w,k*h*nx+j*nx,nx); for(int i=nx; i STA_CAST(int,ny)){ int z=GAMin(STA_CAST(int,nz),d); for(int k=z-1; k>=0; k--){ int j; for(j=ny-1; j>=0; j--) GABinaryString::move(k*h*w+j*w,k*ny*w+j*w,w); for(j=ny; j STA_CAST(int,nz)){ // change in depth is always new bits for(int i=w*h*nz; i> c; if(isdigit(c)){ gene(i++, j, k, ((c == '0') ? 0 : 1)); if(i >= nx){ i=0; j++; } if(j >= ny){ j=0; k++; } } } _evaluated = gaFalse; if(is.eof() && ((k < nz) || // didn't get some lines (j < ny && j != 0) || // didn't get some lines (i < nx && i != 0))){ // didn't get some lines GAErr(GA_LOC, className(), "read", gaErrUnexpectedEOF); is.clear(STD_IOS_BADBIT | is.rdstate()); return 1; } return 0; } // Dump the bits to the stream with a newline at the end of each row and // another at the end of each layer. No newline at the end of the block. int GA3DBinaryStringGenome::write(STD_OSTREAM & os) const { for(unsigned int k=0; k upper) resize(upper,ny,nz); if(nx < lower) resize(lower,ny,nz); break; case HEIGHT: minY = lower; maxY = upper; if(ny > upper) resize(nx,upper,nz); if(ny < lower) resize(nx,lower,nz); break; case DEPTH: minZ = lower; maxZ = upper; if(nz > upper) resize(nx,ny,upper); if(nz < lower) resize(nx,ny,lower); break; default: break; } return resizeBehaviour(which); } void GA3DBinaryStringGenome:: copy(const GA3DBinaryStringGenome & orig, unsigned int r, unsigned int s, unsigned int t, unsigned int x, unsigned int y, unsigned int z, unsigned int w, unsigned int h, unsigned int d) { if(w == 0 || x >= orig.nx || r >= nx || h == 0 || y >= orig.ny || s >= ny || d == 0 || z >= orig.nz || t >= nz) return; if(x + w > orig.nx) w = orig.nx - x; if(y + h > orig.ny) h = orig.ny - y; if(z + d > orig.nz) d = orig.nz - z; if(r + w > nx) w = nx - r; if(s + h > ny) h = ny - s; if(t + d > nz) d = nz - t; for(unsigned int k=0; k nx) w = nx - x; if(y + h > ny) h = ny - y; if(z + d > nz) d = nz - z; for(unsigned int k=0; k nx) w = nx - x; if(y + h > ny) h = ny - y; if(z + d > nz) d = nz - z; for(unsigned int k=0; k nx) w = nx - x; if(y + h > ny) h = ny - y; if(z + d > nz) d = nz - z; for(unsigned int k=0; k nx) w = nx - srcx; if(x + w > nx) w = nx - x; if(srcy + h > ny) h = ny - srcy; if(y + h > ny) h = ny - y; if(srcz + d > nz) d = nz - srcz; if(z + d > nz) d = nz - z; if(srcz=0; k--) for(int j=h-1; j>=0; j--) GABinaryString::move((z+k)*ny*nx + (y+j)*nx + x, (srcz+k)*ny*nx + (srcy+j)*nx + srcx, w); } else{ for(int k=d-1; k>=0; k--) for(unsigned int j=0; j=0; j--) GABinaryString::move((z+k)*ny*nx + (y+j)*nx + x, (srcz+k)*ny*nx + (srcy+j)*nx + srcx, w); } else{ for(unsigned int k=0; k=0; i--) for(int j=child.height()-1; j>=0; j--) for(int k=child.depth()-1; k>=0; k--) child.gene(i,j,k, GARandomBit()); } void GA3DBinaryStringGenome::UnsetInitializer(GAGenome & c) { GA3DBinaryStringGenome &child=DYN_CAST(GA3DBinaryStringGenome &, c); child.resize(GAGenome::ANY_SIZE,GAGenome::ANY_SIZE,GAGenome::ANY_SIZE); child.unset(0, 0, 0, child.width(), child.height(), child.depth()); } void GA3DBinaryStringGenome::SetInitializer(GAGenome & c) { GA3DBinaryStringGenome &child=DYN_CAST(GA3DBinaryStringGenome &, c); child.resize(GAGenome::ANY_SIZE,GAGenome::ANY_SIZE,GAGenome::ANY_SIZE); child.set(0, 0, 0, child.width(), child.height(), child.depth()); } int GA3DBinaryStringGenome::FlipMutator(GAGenome & c, float pmut) { GA3DBinaryStringGenome &child=DYN_CAST(GA3DBinaryStringGenome &, c); register int n, m, i, j, k, d; if(pmut <= 0.0) return(0); float nMut = pmut * STA_CAST(float,child.size()); if(nMut < 1.0){ // we have to do a flip test on each bit nMut = 0; for(i=child.width()-1; i>=0; i--){ for(j=child.height()-1; j>=0; j--){ for(k=child.depth()-1; k>=0; k--){ if(GAFlipCoin(pmut)){ child.gene(i, j, k, ((child.gene(i,j,k) == 0) ? 1 : 0)); nMut++; } } } } } else{ // only flip the number of bits we need to flip for(n=0; n=0; i--) for(int j=sis.height()-1; j>=0; j--) for(int k=sis.depth()-1; k>=0; k--) count += ((sis.gene(i,j,k) == bro.gene(i,j,k)) ? 0 : 1); return count/sis.size(); } // Make sure our bitmask is big enough, generate a mask, then use it to // extract the information from each parent to stuff the two children. // We don't deallocate any space for the masks under the assumption that we'll // have to use them again in the future. // For now we'll implement this only for fixed length genomes. If you use // this crossover method on genomes of different sizes it might break! int GA3DBinaryStringGenome:: UniformCrossover(const GAGenome& p1, const GAGenome& p2, GAGenome* c1, GAGenome* c2){ const GA3DBinaryStringGenome &mom= DYN_CAST(const GA3DBinaryStringGenome &, p1); const GA3DBinaryStringGenome &dad= DYN_CAST(const GA3DBinaryStringGenome &, p2); int i,j,k, nc=0;; if(c1 && c2){ GA3DBinaryStringGenome &sis=DYN_CAST(GA3DBinaryStringGenome &, *c1); GA3DBinaryStringGenome &bro=DYN_CAST(GA3DBinaryStringGenome &, *c2); if(sis.width() == bro.width() && sis.height() == bro.height() && sis.depth() == bro.depth() && mom.width() == dad.width() && mom.height() == dad.height() && mom.depth() == dad.depth() && sis.width() == mom.width() && sis.height() == mom.height() && sis.depth() == mom.depth()){ for(i=sis.width()-1; i>=0; i--){ for(j=sis.height()-1; j>=0; j--){ for(k=sis.depth()-1; k>=0; k--){ if(GARandomBit()){ sis.gene(i,j,k, mom.gene(i,j,k)); bro.gene(i,j,k, dad.gene(i,j,k)); } else{ sis.gene(i,j,k, dad.gene(i,j,k)); bro.gene(i,j,k, mom.gene(i,j,k)); } } } } } else{ GAMask mask; int maxx = GAMax(sis.width(), bro.width()); int minx = GAMin(mom.width(), dad.width()); int maxy = GAMax(sis.height(), bro.height()); int miny = GAMin(mom.height(), dad.height()); int maxz = GAMax(sis.depth(), bro.depth()); int minz = GAMin(mom.depth(), dad.depth()); mask.size(maxx*maxy*maxz); for(i=0; i=0; i--) for(j=miny-1; j>=0; j--) for(k=minz-1; k>=0; k--) sis.gene(i,j,k, (mask[i*miny*minz+j*minz+k] ? mom.gene(i,j,k) : dad.gene(i,j,k))); minx = GAMin(bro.width(), minx); miny = GAMin(bro.height(), miny); minz = GAMin(bro.depth(), minz); for(i=minx-1; i>=0; i--) for(j=miny-1; j>=0; j--) for(k=minz-1; k>=0; k--) bro.gene(i,j,k, (mask[i*miny*minz+j*minz+k] ? dad.gene(i,j,k) : mom.gene(i,j,k))); } nc = 2; } else if(c1 || c2){ GA3DBinaryStringGenome &sis = (c1 ? DYN_CAST(GA3DBinaryStringGenome&, *c1) : DYN_CAST(GA3DBinaryStringGenome&, *c2)); if(mom.width() == dad.width() && mom.height() == dad.height() && mom.depth() == dad.depth() && sis.width() == mom.width() && sis.height() == mom.height() && sis.depth() == mom.depth()){ for(i=sis.width()-1; i>=0; i--) for(j=sis.height()-1; j>=0; j--) for(k=sis.depth()-1; k>=0; k--) sis.gene(i,j,k, (GARandomBit() ? mom.gene(i,j,k):dad.gene(i,j,k))); } else{ int minx = GAMin(mom.width(), dad.width()); int miny = GAMin(mom.height(), dad.height()); int minz = GAMin(mom.depth(), dad.depth()); minx = GAMin(sis.width(), minx); miny = GAMin(sis.height(), miny); minz = GAMin(sis.depth(), minz); for(i=minx-1; i>=0; i--) for(j=miny-1; j>=0; j--) for(k=minz-1; k>=0; k--) sis.gene(i,j,k, (GARandomBit() ? mom.gene(i,j,k):dad.gene(i,j,k))); } nc = 1; } return nc; } // For even crossover we take the even bits from the mother (for the daughter) // and the odd bits from the father. Just the opposite for the son. // This is designed only for genomes that are the same length. If the child // is not the same length as the parent, or if the children are not the same // size, we don't do the crossover. // In the interest of speed we do not do any checks for size. Do not use // this crossover method when the parents and children may be different sizes. // It might break! int GA3DBinaryStringGenome:: EvenOddCrossover(const GAGenome& p1, const GAGenome& p2, GAGenome* c1, GAGenome* c2){ const GA3DBinaryStringGenome &mom= DYN_CAST(const GA3DBinaryStringGenome &, p1); const GA3DBinaryStringGenome &dad= DYN_CAST(const GA3DBinaryStringGenome &, p2); int nc=0; int i,j,k; if(c1 && c2){ GA3DBinaryStringGenome &sis=DYN_CAST(GA3DBinaryStringGenome &, *c1); GA3DBinaryStringGenome &bro=DYN_CAST(GA3DBinaryStringGenome &, *c2); if(sis.width() == bro.width() && sis.height() == bro.height() && sis.depth() == bro.depth() && mom.width() == dad.width() && mom.height() == dad.height() && mom.depth() == dad.depth() && sis.width() == mom.width() && sis.height() == mom.height() && sis.depth() == mom.depth()){ int count=0; for(i=sis.width()-1; i>=0; i--){ for(j=sis.height()-1; j>=0; j--){ for(k=sis.depth()-1; k>=0; k--){ if(count%2 == 0){ sis.gene(i,j,k, mom.gene(i,j,k)); bro.gene(i,j,k, dad.gene(i,j,k)); } else{ sis.gene(i,j,k, dad.gene(i,j,k)); bro.gene(i,j,k, mom.gene(i,j,k)); } count++; } } } } else{ int minx = GAMin(mom.width(), dad.width()); int miny = GAMin(mom.height(), dad.height()); int minz = GAMin(mom.depth(), dad.depth()); minx = GAMin(sis.width(), minx); miny = GAMin(sis.height(), miny); minz = GAMin(sis.depth(), minz); for(i=minx-1; i>=0; i--) for(j=miny-1; j>=0; j--) for(k=minz-1; k>=0; k--) sis.gene(i,j,k, (((i*miny*minz+j*minz+k)%2 == 0) ? mom.gene(i,j,k) : dad.gene(i,j,k))); minx = (bro.width() < minx) ? bro.width() : minx; miny = (bro.height() < miny) ? bro.height() : miny; minz = (bro.depth() < minz) ? bro.depth() : minz; for(i=minx-1; i>=0; i--) for(j=miny-1; j>=0; j--) for(k=minz-1; k>=0; k--) bro.gene(i,j,k, (((i*miny*minz+j*minz+k)%2 == 0) ? dad.gene(i,j,k) : mom.gene(i,j,k))); } nc = 2; } else if(c1 || c2){ GA3DBinaryStringGenome &sis = (c1 ? DYN_CAST(GA3DBinaryStringGenome &, *c1) : DYN_CAST(GA3DBinaryStringGenome &, *c2)); if(mom.width() == dad.width() && mom.height() == dad.height() && mom.depth() == dad.depth() && sis.width() == mom.width() && sis.height() == mom.height() && sis.depth() == mom.depth()){ int count=0; for(i=sis.width()-1; i>=0; i--){ for(j=sis.height()-1; j>=0; j--){ for(k=sis.depth()-1; k>=0; k--){ sis.gene(i,j,k,((count%2 == 0) ? mom.gene(i,j,k):dad.gene(i,j,k))); count++; } } } } else{ int minx = GAMin(mom.width(), dad.width()); int miny = GAMin(mom.height(), dad.height()); int minz = GAMin(mom.depth(), dad.depth()); minx = GAMin(sis.width(), minx); miny = GAMin(sis.height(), miny); minz = GAMin(sis.depth(), minz); for(i=minx-1; i>=0; i--) for(j=miny-1; j>=0; j--) for(k=minz-1; k>=0; k--) sis.gene(i,j, (((i*miny*minz+j*minz+k)%2 == 0) ? mom.gene(i,j,k) : dad.gene(i,j,k))); } nc = 1; } return nc; } // Pick a single point in the 3D block and grab alternating quadrants for each // child. If the children are resizable, this crossover does clipping or // padding depending on the setting of the clip flag. If we pad, we fill the // additional bits with random contents. int GA3DBinaryStringGenome:: OnePointCrossover(const GAGenome& p1, const GAGenome& p2, GAGenome* c1, GAGenome* c2){ const GA3DBinaryStringGenome &mom= DYN_CAST(const GA3DBinaryStringGenome &, p1); const GA3DBinaryStringGenome &dad= DYN_CAST(const GA3DBinaryStringGenome &, p2); int nc=0; unsigned int momsitex, momlenx, momsitey, momleny, momsitez, momlenz; unsigned int dadsitex, dadlenx, dadsitey, dadleny, dadsitez, dadlenz; unsigned int sitex, lenx, sitey, leny, sitez, lenz; if(c1 && c2){ GA3DBinaryStringGenome &sis=DYN_CAST(GA3DBinaryStringGenome &, *c1); GA3DBinaryStringGenome &bro=DYN_CAST(GA3DBinaryStringGenome &, *c2); if(sis.resizeBehaviour(GAGenome::WIDTH) == GAGenome::FIXED_SIZE && bro.resizeBehaviour(GAGenome::WIDTH) == GAGenome::FIXED_SIZE){ if(mom.width() != dad.width() || sis.width() != bro.width() || sis.width() != mom.width()){ GAErr(GA_LOC, mom.className(), "one-point cross", gaErrSameLengthReqd); return nc; } sitex = momsitex = dadsitex = GARandomInt(0, mom.width()); lenx = momlenx = dadlenx = mom.width() - momsitex; } else if(sis.resizeBehaviour(GAGenome::WIDTH) == GAGenome::FIXED_SIZE || bro.resizeBehaviour(GAGenome::WIDTH) == GAGenome::FIXED_SIZE){ GAErr(GA_LOC, mom.className(), "one-point cross", gaErrSameBehavReqd); return nc; } else{ momsitex = GARandomInt(0, mom.width()); dadsitex = GARandomInt(0, dad.width()); momlenx = mom.width() - momsitex; dadlenx = dad.width() - dadsitex; sitex = GAMin(momsitex, dadsitex); lenx = GAMin(momlenx, dadlenx); } if(sis.resizeBehaviour(GAGenome::HEIGHT) == GAGenome::FIXED_SIZE && bro.resizeBehaviour(GAGenome::HEIGHT) == GAGenome::FIXED_SIZE){ if(mom.height() != dad.height() || sis.height() != bro.height() || sis.height() != mom.height()){ GAErr(GA_LOC, mom.className(), "one-point cross", gaErrSameLengthReqd); return nc; } sitey = momsitey = dadsitey = GARandomInt(0, mom.height()); leny = momleny = dadleny = mom.height() - momsitey; } else if(sis.resizeBehaviour(GAGenome::HEIGHT) == GAGenome::FIXED_SIZE || bro.resizeBehaviour(GAGenome::HEIGHT) == GAGenome::FIXED_SIZE){ GAErr(GA_LOC, mom.className(), "one-point cross", gaErrSameBehavReqd); return nc; } else{ momsitey = GARandomInt(0, mom.height()); dadsitey = GARandomInt(0, dad.height()); momleny = mom.height() - momsitey; dadleny = dad.height() - dadsitey; sitey = GAMin(momsitey, dadsitey); leny = GAMin(momleny, dadleny); } if(sis.resizeBehaviour(GAGenome::DEPTH) == GAGenome::FIXED_SIZE && bro.resizeBehaviour(GAGenome::DEPTH) == GAGenome::FIXED_SIZE){ if(mom.depth() != dad.depth() || sis.depth() != bro.depth() || sis.depth() != mom.depth()){ GAErr(GA_LOC, mom.className(), "one-point cross", gaErrSameLengthReqd); return nc; } sitez = momsitez = dadsitez = GARandomInt(0, mom.depth()); lenz = momlenz = dadlenz = mom.depth() - momsitez; } else if(sis.resizeBehaviour(GAGenome::DEPTH) == GAGenome::FIXED_SIZE || bro.resizeBehaviour(GAGenome::DEPTH) == GAGenome::FIXED_SIZE){ GAErr(GA_LOC, mom.className(), "one-point cross", gaErrSameBehavReqd); return nc; } else{ momsitez = GARandomInt(0, mom.depth()); dadsitez = GARandomInt(0, dad.depth()); momlenz = mom.depth() - momsitez; dadlenz = dad.depth() - dadsitez; sitez = GAMin(momsitez, dadsitez); lenz = GAMin(momlenz, dadlenz); } sis.resize(sitex+lenx, sitey+leny, sitez+lenz); bro.resize(sitex+lenx, sitey+leny, sitez+lenz); sis.copy(mom, 0, 0, 0, momsitex-sitex, momsitey-sitey, momsitez-sitez, sitex, sitey, sitez); sis.copy(dad, sitex, 0, 0, dadsitex, dadsitey-sitey, dadsitez-sitez, lenx, sitey, sitez); sis.copy(dad, 0, sitey, 0, dadsitex-sitex, dadsitey, dadsitez-sitez, sitex, leny, sitez); sis.copy(mom, sitex, sitey, 0, momsitex, momsitey, momsitez-sitez, lenx, leny, sitez); sis.copy(dad, 0, 0, sitez, dadsitex-sitex, dadsitey-sitey, dadsitez, sitex, sitey, lenz); sis.copy(mom, sitex, 0, sitez, momsitex, momsitey-sitey, momsitez, lenx, sitey, lenz); sis.copy(mom, 0, sitey, sitez, momsitex-sitex, momsitey, momsitez, sitex, leny, lenz); sis.copy(dad, sitex, sitey, sitez, dadsitex, dadsitey, dadsitez, lenx, leny, lenz); bro.copy(dad, 0, 0, 0, dadsitex-sitex, dadsitey-sitey, dadsitez-sitez, sitex, sitey, sitez); bro.copy(mom, sitex, 0, 0, momsitex, momsitey-sitey, momsitez-sitez, lenx, sitey, sitez); bro.copy(mom, 0, sitey, 0, momsitex-sitex, momsitey, momsitez-sitez, sitex, leny, sitez); bro.copy(dad, sitex, sitey, 0, dadsitex, dadsitey, dadsitez-sitez, lenx, leny, sitez); bro.copy(mom, 0, 0, sitez, momsitex-sitex, momsitey-sitey, momsitez, sitex, sitey, lenz); bro.copy(dad, sitex, 0, sitez, dadsitex, dadsitey-sitey, dadsitez, lenx, sitey, lenz); bro.copy(dad, 0, sitey, sitez, dadsitex-sitex, dadsitey, dadsitez, sitex, leny, lenz); bro.copy(mom, sitex, sitey, sitez, momsitex, momsitey, momsitez, lenx, leny, lenz); nc = 2; } else if(c1 || c2){ GA3DBinaryStringGenome &sis = (c1 ? DYN_CAST(GA3DBinaryStringGenome &, *c1) : DYN_CAST(GA3DBinaryStringGenome &, *c2)); if(sis.resizeBehaviour(GAGenome::WIDTH) == GAGenome::FIXED_SIZE){ if(mom.width() != dad.width() || sis.width() != mom.width()){ GAErr(GA_LOC, mom.className(), "one-point cross", gaErrSameLengthReqd); return nc; } sitex = momsitex = dadsitex = GARandomInt(0, mom.width()); lenx = momlenx = dadlenx = mom.width() - momsitex; } else{ momsitex = GARandomInt(0, mom.width()); dadsitex = GARandomInt(0, dad.width()); momlenx = mom.width() - momsitex; dadlenx = dad.width() - dadsitex; sitex = GAMin(momsitex, dadsitex); lenx = GAMin(momlenx, dadlenx); } if(sis.resizeBehaviour(GAGenome::HEIGHT) == GAGenome::FIXED_SIZE){ if(mom.height() != dad.height() || sis.height() != mom.height()){ GAErr(GA_LOC, mom.className(), "one-point cross", gaErrSameLengthReqd); return nc; } sitey = momsitey = dadsitey = GARandomInt(0, mom.height()); leny = momleny = dadleny = mom.height() - momsitey; } else{ momsitey = GARandomInt(0, mom.height()); dadsitey = GARandomInt(0, dad.height()); momleny = mom.height() - momsitey; dadleny = dad.height() - dadsitey; sitey = GAMin(momsitey, dadsitey); leny = GAMin(momleny, dadleny); } if(sis.resizeBehaviour(GAGenome::DEPTH) == GAGenome::FIXED_SIZE){ if(mom.depth() != dad.depth() || sis.depth() != mom.depth()){ GAErr(GA_LOC, mom.className(), "one-point cross", gaErrSameLengthReqd); return nc; } sitez = momsitez = dadsitez = GARandomInt(0, mom.depth()); lenz = momlenz = dadlenz = mom.depth() - momsitez; } else{ momsitez = GARandomInt(0, mom.depth()); dadsitez = GARandomInt(0, dad.depth()); momlenz = mom.depth() - momsitez; dadlenz = dad.depth() - dadsitez; sitez = GAMin(momsitez, dadsitez); lenz = GAMin(momlenz, dadlenz); } sis.resize(sitex+lenx, sitey+leny, sitez+lenz); if(GARandomBit()){ sis.copy(mom, 0, 0, 0, momsitex-sitex, momsitey-sitey, momsitez-sitez, sitex, sitey, sitez); sis.copy(dad, sitex, 0, 0, dadsitex, dadsitey-sitey, dadsitez-sitez, lenx, sitey, sitez); sis.copy(dad, 0, sitey, 0, dadsitex-sitex, dadsitey, dadsitez-sitez, sitex, leny, sitez); sis.copy(mom, sitex, sitey, 0, momsitex, momsitey, momsitez-sitez, lenx, leny, sitez); sis.copy(dad, 0, 0, sitez, dadsitex-sitex, dadsitey-sitey, dadsitez, sitex, sitey, lenz); sis.copy(mom, sitex, 0, sitez, momsitex, momsitey-sitey, momsitez, lenx, sitey, lenz); sis.copy(mom, 0, sitey, sitez, momsitex-sitex, momsitey, momsitez, sitex, leny, lenz); sis.copy(dad, sitex, sitey, sitez, dadsitex, dadsitey, dadsitez, lenx, leny, lenz); } else{ sis.copy(dad, 0, 0, 0, dadsitex-sitex, dadsitey-sitey, dadsitez-sitez, sitex, sitey, sitez); sis.copy(mom, sitex, 0, 0, momsitex, momsitey-sitey, momsitez-sitez, lenx, sitey, sitez); sis.copy(mom, 0, sitey, 0, momsitex-sitex, momsitey, momsitez-sitez, sitex, leny, sitez); sis.copy(dad, sitex, sitey, 0, dadsitex, dadsitey, dadsitez-sitez, lenx, leny, sitez); sis.copy(mom, 0, 0, sitez, momsitex-sitex, momsitey-sitey, momsitez, sitex, sitey, lenz); sis.copy(dad, sitex, 0, sitez, dadsitex, dadsitey-sitey, dadsitez, lenx, sitey, lenz); sis.copy(dad, 0, sitey, sitez, dadsitex-sitex, dadsitey, dadsitez, sitex, leny, lenz); sis.copy(mom, sitex, sitey, sitez, momsitex, momsitey, momsitez, lenx, leny, lenz); } nc = 1; } return nc; } galib247/ga/GA3DBinStrGenome.h0100644003643600364360000001070410573535473015137 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- binstr3.h mbwall 19apr95 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved DESCRIPTION: This header defines the interface for the 3D binary string genome. ---------------------------------------------------------------------------- */ #ifndef _ga_binstr3_h_ #define _ga_binstr3_h_ #include #include /* ---------------------------------------------------------------------------- 3DBinaryStringGenome ------------------------------------------------------------------------------- ---------------------------------------------------------------------------- */ class GA3DBinaryStringGenome : public GABinaryString, public GAGenome { public: GADefineIdentity("GA3DBinaryStringGenome", GAID::BinaryStringGenome3D); static void UniformInitializer(GAGenome &); static void UnsetInitializer(GAGenome &); static void SetInitializer(GAGenome &); static int FlipMutator(GAGenome &, float); static float BitComparator(const GAGenome&, const GAGenome&); static int UniformCrossover(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*); static int EvenOddCrossover(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*); static int OnePointCrossover(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*); public: GA3DBinaryStringGenome(unsigned int x, unsigned int y, unsigned int z, GAGenome::Evaluator f=(GAGenome::Evaluator)0, void * u=(void *)0); GA3DBinaryStringGenome(const GA3DBinaryStringGenome & orig); GA3DBinaryStringGenome& operator=(const GAGenome& arg) {copy(arg); return *this;} GA3DBinaryStringGenome& operator=(const short array []){ for(unsigned int i=0; i #include #include #define GA_ALLELE_CHUNK 10 template GAAlleleSetCore::GAAlleleSetCore() : type(GAAllele::ENUMERATED), csz(GA_ALLELE_CHUNK), sz(0), SZ(0), a(0) { lowerb = GAAllele::NONE; upperb = GAAllele::NONE; cnt = 1; } template GAAlleleSetCore::GAAlleleSetCore(unsigned int n, const T array []) : type(GAAllele::ENUMERATED), csz(GA_ALLELE_CHUNK), sz(n), SZ(GA_ALLELE_CHUNK) { while(SZ < sz) SZ += csz; a = new T [SZ]; // memcpy(a, array, n*sizeof(T)); for(unsigned int i=0; i GAAlleleSetCore:: GAAlleleSetCore(const T& lower, const T& upper, GAAllele::BoundType lb, GAAllele::BoundType ub) : type(GAAllele::BOUNDED), csz(GA_ALLELE_CHUNK), sz(2), SZ(2), a(new T[2]) { a[0] = lower; a[1] = upper; lowerb = lb; upperb = ub; cnt = 1; } template GAAlleleSetCore:: GAAlleleSetCore(const T& lower, const T& upper, const T& increment, GAAllele::BoundType lb, GAAllele::BoundType ub) : type(GAAllele::DISCRETIZED), csz(GA_ALLELE_CHUNK), sz(3), SZ(3), a(new T[3]) { a[0] = lower; a[1] = upper; a[2] = increment; lowerb = lb; upperb = ub; cnt = 1; } // We do not copy the original's reference count! template GAAlleleSetCore::GAAlleleSetCore(const GAAlleleSetCore & orig) : csz(orig.csz), sz(orig.sz), SZ(orig.SZ), a(new T[orig.SZ]) { // memcpy(a, orig.a, sz*sizeof(T)); for(unsigned int i=0; i GAAlleleSetCore::~GAAlleleSetCore(){ if(cnt > 0) GAErr(GA_LOC, "GAAlleleSetCore", "destructor", gaErrRefsRemain); delete [] a; } // Copying the contents of another allele set core does NOT change the current // count of the allele set core! template GAAlleleSetCore & GAAlleleSetCore::operator=(const GAAlleleSetCore & orig){ if(this == &orig) return *this; if(SZ < orig.sz){ while(SZ < orig.sz) SZ += csz; delete [] a; a = new T [SZ]; } // memcpy(a, orig.a, orig.sz*sizeof(T)); for(unsigned int i=0; i void GAAlleleSet::link(GAAlleleSet& set){ if(&set != this){ if(core != 0){ core->cnt -= 1; if(core->cnt == 0) delete core; } core=set.core; core->cnt += 1; } } template void GAAlleleSet::unlink(){ if(core == 0) return; // nothing to unlink if(core->cnt > 1){ core->cnt -= 1; core = new GAAlleleSetCore(*core); } } // If everthing goes OK, return 0. If there's an error, we return -1. I // really wish there were enough compilers doing exceptions to use them... template int GAAlleleSet::add(const T & alle){ if(core == 0) core = new GAAlleleSetCore; if(core->type != GAAllele::ENUMERATED) return 1; if(core->sz >= core->SZ){ core->SZ += core->csz; T * tmp = core->a; core->a = new T [core->SZ]; for(unsigned int i=0; isz; i++) core->a[i] = tmp[i]; // memcpy(core->a, tmp, core->sz*sizeof(T)); delete [] tmp; } core->a[core->sz] = alle; core->sz += 1; return 0; } template int GAAlleleSet::remove(const T & allele){ if(core == 0) core = new GAAlleleSetCore; if(core->type != GAAllele::ENUMERATED) return 1; for(unsigned int i=0; isz; i++){ if(core->a[i] == allele){ for(unsigned int j=i; jsz-1; j++) core->a[j] = core->a[j+1]; // memmove(&(core->a[i]), &(core->a[i+1]), (core->sz-i-1)*sizeof(T)); core->sz -= 1; i = core->sz; // break out of the loop } } return 0; } template int GAAlleleSet::remove(unsigned int x){ for(unsigned int j=x; jsz-1; j++) core->a[j] = core->a[j+1]; // memmove(&(core->a[i]), &(core->a[i+1]), (core->sz-i-1)*sizeof(T)); core->sz -= 1; return 0; } // When returning an allele from the set, we have to know what type we are. // The allele that we return depends on the type. If we're an enumerated set // then just pick randomly from the list of alleles. If we're a bounded set // then pick randomly from the bounds, and respect the bound types. If we're // a discretized set then we do much as we would for the bounded set, but we // respect the discretization. // Be sure to specialize this member function (see the real genome for an // example of how to do this) template T GAAlleleSet::allele() const { if(core->type == GAAllele::ENUMERATED) return core->a[GARandomInt(0, core->sz-1)]; else if(core->type == GAAllele::DISCRETIZED){ GAErr(GA_LOC, "GAAlleleSet", "allele(unsigned int)", gaErrOpUndef); return core->a[0]; } else{ GAErr(GA_LOC, "GAAlleleSet", "allele(unsigned int)", gaErrOpUndef); return core->a[0]; } } // This works only for enumerated sets. If someone tries to use this on a // non-enumerated set then we post an error message. No bounds checking on // the value that was passed to us, but we do modulo it so that we'll never // break. Also, this means you can wrap an allele set around an array that // is significantly larger than the allele set that defines its contents. template T GAAlleleSet::allele(unsigned int i) const { if(core->type == GAAllele::ENUMERATED) return core->a[i % core->sz]; else if(core->type == GAAllele::DISCRETIZED){ GAErr(GA_LOC, "GAAlleleSet", "allele(unsigned int)", gaErrOpUndef); return core->a[0]; } else{ GAErr(GA_LOC, "GAAlleleSet", "allele(unsigned int)", gaErrNoAlleleIndex); return core->a[0]; } } #ifdef GALIB_USE_STREAMS template int GAAlleleSet::read(STD_ISTREAM&){ GAErr(GA_LOC, "GAAlleleSet", "read", gaErrOpUndef); return 1; } template int GAAlleleSet::write(STD_OSTREAM &) const { GAErr(GA_LOC, "GAAlleleSet", "write", gaErrOpUndef); return 1; } /* // ** won't work with NULL cores!!!!!!! // The default read assumes input in the format that we write out. // We should do more checks on the values that we read in. template int GAAlleleSet::read(STD_ISTREAM& is){ char buf[32]; int n; if(is.fail() || is.eof()) return 1; is.width(sizeof(buf)); // don't allow to overflow buffer is >> buf; if(strcmp(buf, "ENUMERATED") == 0){ core->type = GAAllele::ENUMERATED; is >> n; if(is.fail() || is.eof()) return 1; core->sz = n; if(core->sz >= core->SZ){ while(core->sz >= core->SZ) core->SZ += core->csz; delete [] core->a; core->a = new T [core->SZ]; for(int i=0; isz; i++){ is >> core->a[i]; if(is.fail() || is.eof()) return 1; } } } else if(strcmp(buf, "BOUNDED") == 0){ core->type = GAAllele::BOUNDED; delete [] core->a; core->SZ = 2; core->sz = 2; core->a = new T [core->SZ]; is >> buf; if(strcmp(buf, "INCL") == 0) core->lowerb = GAAllele::INCLUSIVE; else core->lowerb = GAAllele::EXCLUSIVE; is >> buf; if(strcmp(buf, "INCL") == 0) core->upperb = GAAllele::INCLUSIVE; else core->upperb = GAAllele::EXCLUSIVE; is >> core->a[0] >> core->a[1]; if(is.fail() || is.eof()) return 1; } else if(strcmp(buf, "DISCRETIZED") == 0){ core->type = GAAllele::DISCRETIZED; delete [] core->a; core->SZ = 3; core->sz = 3; core->a = new T [core->SZ]; is >> buf; if(strcmp(buf, "INCL") == 0) core->lowerb = GAAllele::INCLUSIVE; else core->lowerb = GAAllele::EXCLUSIVE; is >> buf; if(strcmp(buf, "INCL") == 0) core->upperb = GAAllele::INCLUSIVE; else core->upperb = GAAllele::EXCLUSIVE; is >> core->a[0] >> core->a[1]; if(is.fail() || is.eof()) return 1; } else { is.clear(STD_IOS_BADBIT | is.rdstate()); GAErr(GA_LOC, "GAAlleleSet", "read", "unrecognized allele set type.", "Expected ENUMERATED, BOUNDED, or DISCRETIZED"); return 1; } return 0; } // The default write method prints out the type of the allele set followed by // the contents. We use a single space as our separator. template int GAAlleleSet::write(STD_OSTREAM & os) const { switch(core->type){ case GAAllele::ENUMERATED: os << "ENUMERATED "; os << core->sz << "\n"; for(int i=0; isz; i++) os << core->a[i] << " "; os << "\n"; break; case GAAllele::BOUNDED: os << "BOUNDED "; os << ((core->lowerb == GAAllele::INCLUSIVE) ? "INCL" : "EXCL") << " "; os << ((core->upperb == GAAllele::INCLUSIVE) ? "INCL" : "EXCL") << "\n"; os << core->a[0] << " " << core->a[1] << "\n"; break; case GAAllele::DISCRETIZED: os << "DISCRETIZED "; os << ((core->lowerb == GAAllele::INCLUSIVE) ? "INCL" : "EXCL") << " "; os << ((core->upperb == GAAllele::INCLUSIVE) ? "INCL" : "EXCL") << "\n"; os << core->a[0] << " " << core->a[1] << " " << core->a[2] << "\n"; break; default: break; } return 0; } */ #endif // could do these with a memcmp if the type is simple... template int operator==(const GAAlleleSet & a, const GAAlleleSet & b) { if(a.core == b.core) return 1; if(a.core == 0 || b.core == 0) return 0; if(a.core->sz != b.core->sz) return 0; // return((memcmp(a.core, b.core, a.core->sz * sizeof(T)) == 0) ? 1 : 0); unsigned int i; for(i=0; isz && a.core->a[i] == b.core->a[i]; i++); return((i == a.core->sz) ? 1 : 0); } template int operator!=(const GAAlleleSet & a, const GAAlleleSet & b) { if(a.core == b.core) return 0; if(a.core == 0 || b.core == 0) return 1; if(a.core->sz != b.core->sz) return 1; // return((memcmp(a.core, b.core, a.core->sz * sizeof(T)) == 0) ? 0 : 1); unsigned int i; for(i=0; isz && a.core->a[i] == b.core->a[i]; i++); return((i == a.core->sz) ? 0 : 1); } template GAAlleleSetArray::GAAlleleSetArray() : csz(GA_ALLELE_CHUNK), sz(0), SZ(0), aset(0) {} template GAAlleleSetArray::GAAlleleSetArray(const GAAlleleSet& s) : csz(GA_ALLELE_CHUNK), sz(1), SZ(GA_ALLELE_CHUNK), aset(new GAAlleleSet * [GA_ALLELE_CHUNK]) { aset[0] = new GAAlleleSet(s); } template GAAlleleSetArray::GAAlleleSetArray(const GAAlleleSetArray& orig) : csz(orig.csz), sz(orig.sz), SZ(orig.SZ), aset(new GAAlleleSet * [orig.SZ]) { for(unsigned int i=0; i(orig.set(i)); } template GAAlleleSetArray::~GAAlleleSetArray(){ for(unsigned int i=0; i GAAlleleSetArray& GAAlleleSetArray::operator=(const GAAlleleSetArray& orig){ if(this == &orig) return *this; unsigned int i; for(i=0; i * [SZ]; } for(i=0; i(orig.set(i)); sz = orig.sz; return *this; } // Return 0 if everything goes OK, otherwise return -1 template int GAAlleleSetArray::add(const GAAlleleSet& s){ if(sz+1 > SZ){ SZ += csz; GAAlleleSet** tmp = aset; aset = new GAAlleleSet * [SZ]; memcpy(aset, tmp, sz * sizeof(GAAlleleSet*)); delete [] tmp; } aset[sz] = new GAAlleleSet(s); sz++; return 0; } template int GAAlleleSetArray::add(unsigned int n, const T a[]){ if(sz+1 > SZ){ SZ += csz; GAAlleleSet** tmp = aset; aset = new GAAlleleSet * [SZ]; memcpy(aset, tmp, sz * sizeof(GAAlleleSet*)); delete [] tmp; } aset[sz] = new GAAlleleSet(n, a); sz++; return 0; } template int GAAlleleSetArray::add(const T& lower, const T& upper, GAAllele::BoundType lb, GAAllele::BoundType ub){ if(sz+1 > SZ){ SZ += csz; GAAlleleSet** tmp = aset; aset = new GAAlleleSet * [SZ]; memcpy(aset, tmp, sz * sizeof(GAAlleleSet*)); delete [] tmp; } aset[sz] = new GAAlleleSet(lower,upper,lb,ub); sz++; return 0; } template int GAAlleleSetArray::add(const T& lower, const T& upper, const T& increment, GAAllele::BoundType lb, GAAllele::BoundType ub){ if(sz+1 > SZ){ SZ += csz; GAAlleleSet** tmp = aset; aset = new GAAlleleSet * [SZ]; memcpy(aset, tmp, sz * sizeof(GAAlleleSet*)); delete [] tmp; } aset[sz] = new GAAlleleSet(lower,upper,increment,lb,ub); sz++; return 0; } template int GAAlleleSetArray::remove(unsigned int n){ if(n >= sz) return 1; delete aset[n]; for(unsigned int i=n; i #include #include class GAAllele { public: enum Type {ENUMERATED=1, BOUNDED=2, DISCRETIZED}; enum BoundType {NONE, INCLUSIVE, EXCLUSIVE}; }; /* ---------------------------------------------------------------------------- This object contains a set of alleles for use with a similarly typed genome. This object can be used with any type that has operator= defined for it. If you use the remove member then you must have operator== defined for it. This should be implemented as a derivative of the Array class? But I don't want that overhead at this point. Also, behaviour is not the same. The allele set uses the envelope/message structure. The core allele object is a reference-counted structure that contains all of the guts of an allele set. The outer shell, the allele set itself, is what users actually see. It defines the interface. With this setup you can create a single allele set then each genome does not have to make its own copy. And we don't have to worry about an allele set going out of scope then leaving genomes hanging (a problem if we just used a pointer to a single alleleset with no reference counting). You can link an allele set to another so that they share the same core. Use the 'link' member function (this is typically used within the GAlib to reduce the number of actual alleleset instances when cloning populations of genomes). There is no way to 'resize' an allele set. You must add to it or remove elements from it. The base template class assumes that the objects in the allele set are complex, i.e. it is not OK to do a bit-copy of each object. We should do specializations for non-complex objects (or perhaps a separate class that does bit-copies rather than logical-copies?) When you clone an allele set, the new one has its own core. Why didn't I do this as a couple of objects (enumerated set, bounded set, discretized set, etc)? I wanted to be able to have an array that uses sets of many different types. I suppose the allele set should be completely polymorphic like the rest of the GAlib objects, but for now we'll do it as a single object with multiple personalities (and a state). There is no error checking. You should check the type before you try to call any of the member functions. In particular, if you try to get the bounds on an enumerated set of one element, it will break. *** should the assignment operator check to be sure that no allele is duplicated, or is it OK to have duplicate alleles in a set? For now we allow duplicates (via either the add or assignemnt ops). ---------------------------------------------------------------------------- */ template class GAAlleleSetCore { public: GAAlleleSetCore(); GAAlleleSetCore(unsigned int n, const T array []); GAAlleleSetCore(const T& lower, const T& upper, GAAllele::BoundType lb=GAAllele::INCLUSIVE, GAAllele::BoundType ub=GAAllele::INCLUSIVE); GAAlleleSetCore(const T& lower, const T& upper, const T& increment, GAAllele::BoundType lb=GAAllele::INCLUSIVE, GAAllele::BoundType ub=GAAllele::INCLUSIVE); GAAlleleSetCore(const GAAlleleSetCore&); virtual ~GAAlleleSetCore(); GAAlleleSetCore& operator=(const GAAlleleSetCore&); GAAllele::Type type; // is this an ennumerated or bounded set? GAAllele::BoundType lowerb, upperb; // what kind of limit is the bound? unsigned int cnt; // how many objects are using us? unsigned int csz; // how big are the chunks to allocate? unsigned int sz; // number we have unsigned int SZ; // how many have we allocated? T * a; }; #if defined(GALIB_USE_COMP_OPERATOR_TEMPLATES) template int operator==(const T &, const T &); template int operator!=(const T &, const T &); #endif template class GAAlleleSet { public: GAAlleleSet() : core(0) {} GAAlleleSet(unsigned int n, const T a[]) : core(new GAAlleleSetCore(n,a)) {} GAAlleleSet(const T& lower, const T& upper, GAAllele::BoundType lb=GAAllele::INCLUSIVE, GAAllele::BoundType ub=GAAllele::INCLUSIVE) : core(new GAAlleleSetCore(lower, upper, lb, ub)) {} GAAlleleSet(const T& lower, const T& upper, const T& increment, GAAllele::BoundType lb=GAAllele::INCLUSIVE, GAAllele::BoundType ub=GAAllele::INCLUSIVE) : core(new GAAlleleSetCore(lower, upper, increment, lb, ub)) {} GAAlleleSet(const GAAlleleSet& set) : core(new GAAlleleSetCore(*(set.core))) {} virtual ~GAAlleleSet(){ if(core != 0){ core->cnt -= 1; if(core->cnt==0) delete core; } } GAAlleleSet & operator=(const GAAlleleSet& set){ if(this == &set) return *this; if(core) *core = *set.core; else core = new GAAlleleSetCore(*(set.core)); return *this; } GAAlleleSet * clone() const {return new GAAlleleSet(*this);} void link(GAAlleleSet& set); void unlink(); int size() const {return core->sz;} // only meaninful for enumerated sets int add(const T&); // only for enumerated sets int remove(const T&); // only for enumerated sets int remove(unsigned int); // only for enumerated sets T allele() const; // ok for any type of set T allele(unsigned int i) const; // only for enumerated sets T lower() const {return core->a[0];} // only for bounded sets T upper() const {return core->a[1];} T inc() const {return core->a[2];} GAAllele::BoundType lowerBoundType() const {return core->lowerb;} GAAllele::BoundType upperBoundType() const {return core->upperb;} GAAllele::Type type() const {return core->type;} #ifdef GALIB_USE_STREAMS int read(STD_ISTREAM &); int write(STD_OSTREAM & os) const; #endif #if defined(THINK_C) friend operator==(const GAAlleleSet &, const GAAlleleSet &); friend operator!=(const GAAlleleSet &, const GAAlleleSet &); #elif defined(GALIB_USE_EMPTY_TEMPLATES) friend int operator==<>(const GAAlleleSet &, const GAAlleleSet &); friend int operator!=<>(const GAAlleleSet &, const GAAlleleSet &); #elif defined(GALIB_USE_NAMED_TEMPLATES) friend int operator==(const GAAlleleSet &, const GAAlleleSet &); friend int operator!=(const GAAlleleSet &, const GAAlleleSet &); #else friend int operator==(const GAAlleleSet &, const GAAlleleSet &); friend int operator!=(const GAAlleleSet &, const GAAlleleSet &); #endif protected: GAAlleleSetCore *core; }; template class GAAlleleSetArray { public: GAAlleleSetArray(); GAAlleleSetArray(const GAAlleleSet& s); GAAlleleSetArray(const GAAlleleSetArray&); virtual ~GAAlleleSetArray(); GAAlleleSetArray& operator=(const GAAlleleSetArray&); int size() const {return sz;} const GAAlleleSet& set(unsigned int i) const {return *(aset[i]);} int add(const GAAlleleSet& s); int add(unsigned int n, const T a[]); int add(const T& lower, const T& upper, GAAllele::BoundType lb=GAAllele::INCLUSIVE, GAAllele::BoundType ub=GAAllele::INCLUSIVE); int add(const T& lower, const T& upper, const T& increment, GAAllele::BoundType lb=GAAllele::INCLUSIVE, GAAllele::BoundType ub=GAAllele::INCLUSIVE); int remove(unsigned int); protected: unsigned int csz; unsigned int sz; unsigned int SZ; GAAlleleSet **aset; }; #ifdef GALIB_USE_STREAMS template STD_OSTREAM & operator<< (STD_OSTREAM & os, const GAAlleleSet & arg) { arg.write(os); return os; } template STD_ISTREAM & operator>> (STD_ISTREAM & is, GAAlleleSet & arg) { arg.read(is); return is; } #endif #ifdef GALIB_USE_BORLAND_INST #include #endif #endif galib247/ga/GAArray.h0100644003643600364360000000604610573535474013477 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- arraytmpl.h mbwall 22apr95 Copyright 1995 Massachusetts Institute of Technology DESCRIPTION: This defines the array base class. Be careful what you put into one of these arrays! This class can be used only on objects that have: a default constructor (takes no arguments) operator= operator== operator!= In other words, use only primitive objects in this array (e.g. int, float, pointers, etc) The constructor will try to initialize to zero, but only if the type is right. We don't do any over-allocation, so resizing can be expensive. No error checking on the copy, so don't walk over end of array! TODO: should do specialization for simple types that does memcpy rather than loop ---------------------------------------------------------------------------- */ #ifndef _ga_arraytmpl_h_ #define _ga_arraytmpl_h_ template class GAArray { public: GAArray(unsigned int s) : sz(s), a(sz ? new T[sz] : 0) {for(unsigned int i=0; i & orig){sz=0; a=(T *)0; copy(orig);} GAArray & operator=(const GAArray & orig){copy(orig); return *this;} GAArray & operator=(const T array []) // no err checks! {for(unsigned int i=0; i * clone(){return new GAArray(*this);} operator const T * () const {return a;} operator T * () {return a;} const T & operator[](unsigned int i) const {return a[i];} T & operator[](unsigned int i) {return a[i];} void copy(const GAArray & orig){ size(orig.sz); for(unsigned int i=0; i & orig, unsigned int dest, unsigned int src, unsigned int length){ for(unsigned int i=0; i dest) for(unsigned int i=0; i=0; i--) tmp[i] = a[i]; delete [] a; a = tmp; return sz=n; } int equal(const GAArray & b, unsigned int dest, unsigned int src, unsigned int length) const { for(unsigned int i=0; i int operator==(const GAArray & a, const GAArray & b){ if(a.size() != b.size()) return 0; return a.equal(b,0,0,a.sz); } template int operator!=(const GAArray & a, const GAArray & b){ if(a.size() != b.size()) return 1; return a.equal(b,0,0,a.sz) ? 0 : 1; } #endif galib247/ga/GABaseGA.C0100644003643600364360000004403310573535474013434 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- gabase.C mbwall 28jul94 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved Source file for the base genetic algorithm object. ---------------------------------------------------------------------------- */ #include #include #include #include #include // gets the RCS string in for ident purposes //#define GA_DEBUG // Here we assign the default values of the GAlib default parameters. int gaDefNumGen = 250; float gaDefPConv = 0.99; int gaDefNConv = 20; float gaDefPMut = 0.01; float gaDefPCross = 0.90; int gaDefPopSize = 50; int gaDefNPop = 10; float gaDefPRepl = 0.5; int gaDefNRepl = 10; int gaDefNumOff = 2; float gaDefPMig = 0.1; int gaDefNMig = 5; int gaDefSelectScores = GAStatistics::Maximum; int gaDefMiniMaxi = 1; GABoolean gaDefDivFlag = gaFalse; GABoolean gaDefElitism = gaTrue; int gaDefSeed = 0; // return the configuration string that identifies this build of the library. static const char* rcsid = GALIB_LIBRARY_IDENTIFIER; const char* GAConfig() { return rcsid; } // Here are a few termination functions that you can use. Terminators return // gaTrue if the algorithm should finish, gaFalse otherwise. GABoolean GAGeneticAlgorithm::TerminateUponGeneration(GAGeneticAlgorithm & ga){ return(ga.generation() < ga.nGenerations() ? gaFalse : gaTrue); } // If we are maximizing, then terminate when the convergence has exceeded the // specified convergence. If we are minimizing, then terminate when the // convergence has dropped below the specified convergence. GABoolean GAGeneticAlgorithm::TerminateUponConvergence(GAGeneticAlgorithm & ga){ GABoolean val = gaFalse; if(ga.minimaxi() == GAGeneticAlgorithm::MINIMIZE) { if(ga.convergence() == 0 || ga.convergence() > ga.pConvergence()) val = gaFalse; else val = gaTrue; } else { if(ga.convergence() < ga.pConvergence()) val = gaFalse; else val = gaTrue; } return val; } // Use the ratio between the minimum and maximum to determine whether the // population has converged. This method will not work if the values cross // zero! // Note that this is significantly different than the definition (and the // bug-laden implementation) that was in version of GAlib prior to 2.4.5. // // For historical purposes, here is the old definition of this method: // // Use the ratio of the population mean divided by the population maximum to // determine whether the population has converged. If we are maximizing, then // check to see if the ratio exceeds the convergence. If we are minimizing, // then check to see if the ratio has dropped below the convergence. GABoolean GAGeneticAlgorithm::TerminateUponPopConvergence(GAGeneticAlgorithm & ga){ GABoolean val = gaFalse; if(ga.statistics().current(GAStatistics::Maximum) == 0) { return val; } float ratio = ga.statistics().current(GAStatistics::Minimum) / ga.statistics().current(GAStatistics::Maximum); if(ga.minimaxi() == GAGeneticAlgorithm::MINIMIZE) { if(ratio <= ga.pConvergence()) val = gaTrue; else val = gaFalse; } else { if(ratio >= ga.pConvergence()) val = gaTrue; else val = gaFalse; } return val; } GAParameterList& GAGeneticAlgorithm::registerDefaultParameters(GAParameterList& p) { p.add(gaNseed, gaSNseed, GAParameter::INT, &gaDefSeed); p.add(gaNminimaxi, gaSNminimaxi, GAParameter::INT, &gaDefMiniMaxi); p.add(gaNnGenerations, gaSNnGenerations, GAParameter::INT, &gaDefNumGen); p.add(gaNnConvergence, gaSNnConvergence, GAParameter::INT, &gaDefNConv); p.add(gaNpConvergence, gaSNpConvergence, GAParameter::FLOAT, &gaDefPConv); p.add(gaNpCrossover, gaSNpCrossover, GAParameter::FLOAT, &gaDefPCross); p.add(gaNpMutation, gaSNpMutation, GAParameter::FLOAT, &gaDefPMut); p.add(gaNpopulationSize, gaSNpopulationSize, GAParameter::INT, &gaDefPopSize); p.add(gaNnBestGenomes, gaSNnBestGenomes, GAParameter::INT, &gaDefNumBestGenomes); p.add(gaNscoreFrequency, gaSNscoreFrequency, GAParameter::INT, &gaDefScoreFrequency1); p.add(gaNflushFrequency, gaSNflushFrequency, GAParameter::INT, &gaDefFlushFrequency); p.add(gaNrecordDiversity, gaSNrecordDiversity, GAParameter::INT, &gaDefDivFlag); p.add(gaNscoreFilename, gaSNscoreFilename, GAParameter::STRING, gaDefScoreFilename); p.add(gaNselectScores, gaSNselectScores, GAParameter::INT, &gaDefSelectScores); return p; } // When we create a GA, we stuff the parameters with the basics that will be // needed by most genetic algorithms - num generations, p convergence, etc. GAGeneticAlgorithm::GAGeneticAlgorithm(const GAGenome& g) : stats(), params() { pop = new GAPopulation(g, gaDefPopSize); pop->geneticAlgorithm(*this); ud = (void *)0; cf = GAGeneticAlgorithm::DEFAULT_TERMINATOR; d_seed = gaDefSeed; params.add(gaNseed, gaSNseed, GAParameter::INT, &d_seed); minmax = gaDefMiniMaxi; params.add(gaNminimaxi, gaSNminimaxi, GAParameter::INT, &minmax); ngen = gaDefNumGen; params.add(gaNnGenerations, gaSNnGenerations, GAParameter::INT, &ngen); nconv = gaDefNConv; stats.nConvergence(nconv); params.add(gaNnConvergence, gaSNnConvergence, GAParameter::INT, &nconv); pconv = gaDefPConv; params.add(gaNpConvergence, gaSNpConvergence, GAParameter::FLOAT, &pconv); pcross = gaDefPCross; params.add(gaNpCrossover, gaSNpCrossover, GAParameter::FLOAT, &pcross); pmut = gaDefPMut; params.add(gaNpMutation, gaSNpMutation, GAParameter::FLOAT, &pmut); int psize = pop->size(); params.add(gaNpopulationSize, gaSNpopulationSize, GAParameter::INT, &psize); stats.scoreFrequency(gaDefScoreFrequency1); params.add(gaNscoreFrequency, gaSNscoreFrequency, GAParameter::INT, &gaDefScoreFrequency1); stats.flushFrequency(gaDefFlushFrequency); params.add(gaNflushFrequency, gaSNflushFrequency, GAParameter::INT, &gaDefFlushFrequency); stats.recordDiversity(gaDefDivFlag); params.add(gaNrecordDiversity, gaSNrecordDiversity, GAParameter::INT, &gaDefDivFlag); stats.scoreFilename(gaDefScoreFilename); params.add(gaNscoreFilename, gaSNscoreFilename, GAParameter::STRING, gaDefScoreFilename); stats.selectScores(gaDefSelectScores); params.add(gaNselectScores, gaSNselectScores, GAParameter::INT, &gaDefSelectScores); stats.nBestGenomes(g, gaDefNumBestGenomes); params.add(gaNnBestGenomes, gaSNnBestGenomes, GAParameter::INT, &gaDefNumBestGenomes); scross = g.sexual(); across = g.asexual(); } GAGeneticAlgorithm::GAGeneticAlgorithm(const GAPopulation& p) : stats(), params() { pop = new GAPopulation(p); pop->geneticAlgorithm(*this); ud = (void *)0; cf = GAGeneticAlgorithm::DEFAULT_TERMINATOR; d_seed = gaDefSeed; params.add(gaNseed, gaSNseed, GAParameter::INT, &d_seed); minmax = gaDefMiniMaxi; params.add(gaNminimaxi, gaSNminimaxi, GAParameter::INT, &minmax); ngen = gaDefNumGen; params.add(gaNnGenerations, gaSNnGenerations, GAParameter::INT, &ngen); nconv = gaDefNConv; stats.nConvergence(nconv); params.add(gaNnConvergence, gaSNnConvergence, GAParameter::INT, &nconv); pconv = gaDefPConv; params.add(gaNpConvergence, gaSNpConvergence, GAParameter::FLOAT, &pconv); pcross = gaDefPCross; params.add(gaNpCrossover, gaSNpCrossover, GAParameter::FLOAT, &pcross); pmut = gaDefPMut; params.add(gaNpMutation, gaSNpMutation, GAParameter::FLOAT, &pmut); int psize = pop->size(); params.add(gaNpopulationSize, gaSNpopulationSize, GAParameter::INT, &psize); stats.scoreFrequency(gaDefScoreFrequency1); params.add(gaNscoreFrequency, gaSNscoreFrequency, GAParameter::INT, &gaDefScoreFrequency1); stats.flushFrequency(gaDefFlushFrequency); params.add(gaNflushFrequency, gaSNflushFrequency, GAParameter::INT, &gaDefFlushFrequency); stats.recordDiversity(gaDefDivFlag); params.add(gaNrecordDiversity, gaSNrecordDiversity, GAParameter::INT, &gaDefDivFlag); stats.scoreFilename(gaDefScoreFilename); params.add(gaNscoreFilename, gaSNscoreFilename, GAParameter::STRING, gaDefScoreFilename); stats.selectScores(gaDefSelectScores); params.add(gaNselectScores, gaSNselectScores, GAParameter::INT, &gaDefSelectScores); stats.nBestGenomes(p.individual(0), gaDefNumBestGenomes); params.add(gaNnBestGenomes, gaSNnBestGenomes, GAParameter::INT, &gaDefNumBestGenomes); scross = p.individual(0).sexual(); across = p.individual(0).asexual(); } GAGeneticAlgorithm::GAGeneticAlgorithm(const GAGeneticAlgorithm& ga) : stats(ga.stats), params(ga.params){ pop = ga.pop->clone(); pop->geneticAlgorithm(*this); cf = ga.cf; ud = ga.ud; ngen = ga.ngen; nconv = ga.nconv; pconv = ga.pconv; pcross = ga.pcross; pmut = ga.pmut; minmax = ga.minmax; scross = ga.scross; across = ga.across; d_seed = ga.d_seed; } GAGeneticAlgorithm::~GAGeneticAlgorithm() { delete pop; } void GAGeneticAlgorithm::copy(const GAGeneticAlgorithm& ga) { if(pop) pop->copy(*(ga.pop)); else pop = ga.pop->clone(); pop->geneticAlgorithm(*this); stats = ga.stats; params = ga.params; cf = ga.cf; ud = ga.ud; ngen = ga.ngen; nconv = ga.nconv; pconv = ga.pconv; pcross = ga.pcross; pmut = ga.pmut; minmax = ga.minmax; scross = ga.scross; across = ga.across; d_seed = ga.d_seed; } const GAParameterList& GAGeneticAlgorithm::parameters(const GAParameterList& list){ for(int i=0; isize(); status = 0; } else if(strcmp(name, gaNminimaxi) == 0 || strcmp(name, gaSNminimaxi) == 0){ *((int*)value) = minmax; status = 0; } else if(strcmp(name, gaNnGenerations) == 0 || strcmp(name, gaSNnGenerations) == 0){ *((int*)value) = ngen; status = 0; } else if(strcmp(name, gaNpConvergence) == 0 || strcmp(name, gaSNpConvergence) == 0){ *((float*)value) = pconv; status = 0; } else if(strcmp(name, gaNnConvergence) == 0 || strcmp(name, gaSNnConvergence) == 0){ *((int*)value) = nconv; status = 0; } else if(strcmp(name, gaNpCrossover) == 0 || strcmp(name, gaSNpCrossover) == 0){ *((float*)value) = pcross; status = 0; } else if(strcmp(name, gaNpMutation) == 0 || strcmp(name, gaSNpMutation) == 0){ *((float*)value) = pmut; status = 0; } else if(strcmp(name,gaNscoreFrequency) == 0 || strcmp(name,gaSNscoreFrequency) == 0){ *((int*)value) = stats.scoreFrequency(); status = 0; } else if(strcmp(name,gaNflushFrequency) == 0 || strcmp(name,gaSNflushFrequency) == 0){ *((int*)value) = stats.flushFrequency(); status = 0; } else if(strcmp(name,gaNrecordDiversity) == 0 || strcmp(name,gaSNrecordDiversity) == 0){ *((int*)value) = stats.recordDiversity(); status = 0; } else if(strcmp(name,gaNselectScores) == 0 || strcmp(name,gaSNselectScores)==0){ *((int*)value) = stats.selectScores(); status = 0; } else if(strcmp(name,gaNscoreFilename) == 0 || strcmp(name,gaSNscoreFilename) == 0){ *((const char**)value) = stats.scoreFilename(); status = 0; } return status; } void GAGeneticAlgorithm::objectiveFunction(GAGenome::Evaluator f){ for(int i=0; isize(); i++) pop->individual(i).evaluator(f); } void GAGeneticAlgorithm::objectiveData(const GAEvalData& v){ for(int i=0; isize(); i++) pop->individual(i).evalData(v); } const GAPopulation& GAGeneticAlgorithm::population(const GAPopulation& p) { if(p.size() < 1) { GAErr(GA_LOC, className(), "population", gaErrNoIndividuals); return *pop; } pop->copy(p); pop->geneticAlgorithm(*this); return *pop; } int GAGeneticAlgorithm::populationSize(unsigned int value){ unsigned int ps = value; params.set(gaNpopulationSize, value); return pop->size(ps); } int GAGeneticAlgorithm::minimaxi(int m) { if(m == MINIMIZE) pop->order(GAPopulation::LOW_IS_BEST); else pop->order(GAPopulation::HIGH_IS_BEST); params.set(gaNminimaxi, m); minmax = (m == MINIMIZE ? MINIMIZE : MAXIMIZE); return minmax; } galib247/ga/GABaseGA.h0100644003643600364360000002371510573535473013504 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- gabase.h mbwall 28jul94 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved Header for the base genetic algorithm class. ---------------------------------------------------------------------------- */ #ifndef _ga_gabase_h_ #define _ga_gabase_h_ #include #include #include #include #include #include // When specifying parameters for a GAlib object, you can use the fullname (the // name used in parameters data files) or the short name (the name typically // used on the command line). When specifying parameters in your code you can // use a string, or use the predefined macros below (kind of like using the // resource/class names in Motif for you Xt jocks). #define gaNnGenerations "number_of_generations" #define gaSNnGenerations "ngen" #define gaNpConvergence "convergence_percentage" #define gaSNpConvergence "pconv" #define gaNnConvergence "generations_to_convergence" #define gaSNnConvergence "nconv" #define gaNpCrossover "crossover_probability" #define gaSNpCrossover "pcross" #define gaNpMutation "mutation_probability" #define gaSNpMutation "pmut" #define gaNpopulationSize "population_size" #define gaSNpopulationSize "popsize" #define gaNnPopulations "number_of_populations" #define gaSNnPopulations "npop" #define gaNpReplacement "replacement_percentage" #define gaSNpReplacement "prepl" #define gaNnReplacement "replacement_number" #define gaSNnReplacement "nrepl" #define gaNnBestGenomes "number_of_best" #define gaSNnBestGenomes "nbest" #define gaNscoreFrequency "score_frequency" #define gaSNscoreFrequency "sfreq" #define gaNflushFrequency "flush_frequency" #define gaSNflushFrequency "ffreq" #define gaNscoreFilename "score_filename" #define gaSNscoreFilename "sfile" #define gaNselectScores "select_scores" #define gaSNselectScores "sscores" #define gaNelitism "elitism" #define gaSNelitism "el" #define gaNnOffspring "number_of_offspring" #define gaSNnOffspring "noffspr" #define gaNrecordDiversity "record_diversity" #define gaSNrecordDiversity "recdiv" #define gaNpMigration "migration_percentage" #define gaSNpMigration "pmig" #define gaNnMigration "migration_number" #define gaSNnMigration "nmig" #define gaNminimaxi "minimaxi" #define gaSNminimaxi "mm" #define gaNseed "seed" #define gaSNseed "seed" extern int gaDefNumGen; extern float gaDefPConv; extern int gaDefNConv; extern float gaDefPMut; extern float gaDefPCross; extern int gaDefPopSize; extern int gaDefNPop; extern float gaDefPRepl; extern int gaDefNRepl; extern int gaDefNumOff; extern float gaDefPMig; extern int gaDefNMig; extern int gaDefSelectScores; extern int gaDefMiniMaxi; extern GABoolean gaDefDivFlag; extern GABoolean gaDefElitism; extern int gaDefSeed; /* ---------------------------------------------------------------------------- The base GA class is virtual - it defines the core data elements and parts of the interface that are common to all genetic algorithms (as defined in GAlib, that is). initialize Undefined for the base class. The initialization routine typically calls the population initializer (which typically calls the genome initializers). It should also reset the statistics. step Evolve by one generation. 'generation' can be defined different ways for different genetic algorithms, but in the traditional formulation a generation mean creation of a new population (or portion thereof). done Calls the completion measure routine to tell whether or not the GA is done. evolve This method is provided as a convenience so that you don't have to increment the GA generation-by-generation by hand. If you do decide to do it by hand, be sure that you initialize before you start evolving! ---------------------------------------------------------------------------- */ class GAGeneticAlgorithm : public GAID { public: GADefineIdentity("GAIncrementalGA", GAID::BaseGA); typedef GABoolean (*Terminator)(GAGeneticAlgorithm & ga); enum { MINIMIZE=-1, MAXIMIZE=1 }; static GAParameterList& registerDefaultParameters(GAParameterList&); static GABoolean TerminateUponGeneration(GAGeneticAlgorithm &); static GABoolean TerminateUponConvergence(GAGeneticAlgorithm &); static GABoolean TerminateUponPopConvergence(GAGeneticAlgorithm &); public: GAGeneticAlgorithm(const GAGenome&); GAGeneticAlgorithm(const GAPopulation&); GAGeneticAlgorithm(const GAGeneticAlgorithm&); virtual ~GAGeneticAlgorithm(); virtual void copy(const GAGeneticAlgorithm&); GABoolean done(){ return (*cf)(*this); } virtual void initialize(unsigned int seed=0) =0; virtual void step() =0; virtual void evolve(unsigned int seed=0){ initialize(seed); while(!done()){step();} if(stats.flushFrequency() > 0) stats.flushScores(); } #ifdef GALIB_USE_STREAMS virtual int write(const char*) const {return 0;} virtual int write(STD_OSTREAM &) const {return 0;} virtual int read(const char*){return 0;} virtual int read(STD_ISTREAM &){return 0;} #endif void * userData() const {return ud;} void * userData(void * d){return ud=d;} Terminator terminator() const {return cf;} Terminator terminator(Terminator f){return cf=f;} const GAParameterList& parameters() const { return params; } const GAParameterList& parameters(const GAParameterList&); const GAParameterList& parameters(int&, char **, GABoolean flag=gaFalse); #ifdef GALIB_USE_STREAMS const GAParameterList& parameters(const char* filename, GABoolean f=gaFalse); const GAParameterList& parameters(STD_ISTREAM &, GABoolean flag=gaFalse); #endif virtual int get(const char*, void*) const; virtual int setptr(const char*, const void*); int set(const char* s, int v) { return setptr(s, (void*)&v); } int set(const char* s, unsigned int v) { return setptr(s, (void*)&v); } int set(const char* s, char v) { return setptr(s, (void*)&v); } int set(const char* s, const char* v) { return setptr(s, (void*)v); } int set(const char* s, const void* v) { return setptr(s, v); } int set(const char* s, double v); virtual int minimaxi() const {return minmax;} virtual int minimaxi(int m); int minimize() {return minimaxi(MINIMIZE);} int maximize() {return minimaxi(MAXIMIZE);} int nGenerations() const {return ngen;} int nGenerations(unsigned int n) {params.set(gaNnGenerations, n); return ngen = n;} int nConvergence() const {return nconv;} int nConvergence(unsigned int n) {params.set(gaNnConvergence, n); return nconv = stats.nConvergence(n);} float pConvergence() const {return pconv;} float pConvergence(float p) {params.set(gaNpConvergence, p); return pconv = p;} float pCrossover() const {return pcross;} float pCrossover(float p) {params.set(gaNpCrossover, p); return pcross = p;} float pMutation() const {return pmut;} float pMutation(float p) {params.set(gaNpMutation, p); return pmut = p;} GAGenome::SexualCrossover crossover(GAGenome::SexualCrossover f) {return scross=f;} GAGenome::SexualCrossover sexual() const {return scross;} GAGenome::AsexualCrossover crossover(GAGenome::AsexualCrossover f) {return across=f;} GAGenome::AsexualCrossover asexual() const {return across;} const GAStatistics & statistics() const {return stats;} float convergence() const {return stats.convergence();} int generation() const {return stats.generation();} void flushScores() {if(stats.flushFrequency() > 0) stats.flushScores();} int scoreFrequency() const {return stats.scoreFrequency();} int scoreFrequency(unsigned int x) {params.set(gaNscoreFrequency, x); return stats.scoreFrequency(x);} int flushFrequency() const {return stats.flushFrequency();} int flushFrequency(unsigned int x) {params.set(gaNflushFrequency, x); return stats.flushFrequency(x);} const char* scoreFilename() const {return stats.scoreFilename();} const char* scoreFilename(const char* fn) {params.set(gaNscoreFilename, fn); return stats.scoreFilename(fn);} int selectScores(){return stats.selectScores();} int selectScores(int w) {params.set(gaNselectScores, w); return stats.selectScores(w);} GABoolean recordDiversity() const {return stats.recordDiversity();} GABoolean recordDiversity(GABoolean f) {params.set(gaNrecordDiversity, (int)f); return stats.recordDiversity(f);} virtual const GAPopulation& population() const {return *pop;} virtual const GAPopulation& population(const GAPopulation&); virtual int populationSize() const {return pop->size();} virtual int populationSize(unsigned int n); virtual int nBestGenomes() const {return stats.nBestGenomes();} virtual int nBestGenomes(unsigned int n) { params.set(gaNnBestGenomes, n); return stats.nBestGenomes(pop->individual(0), n); } virtual GAScalingScheme& scaling() const {return pop->scaling();} virtual GAScalingScheme& scaling(const GAScalingScheme & s) {return pop->scaling(s);} virtual GASelectionScheme& selector() const {return pop->selector(); } virtual GASelectionScheme& selector(const GASelectionScheme& s) {return pop->selector(s);} virtual void objectiveFunction(GAGenome::Evaluator f); virtual void objectiveData(const GAEvalData& v); protected: GAStatistics stats; GAParameterList params; GAPopulation *pop; Terminator cf; // function for determining done-ness void * ud; // pointer to user data structure int d_seed; unsigned int ngen; unsigned int nconv; float pconv; float pcross; float pmut; int minmax; GAGenome::SexualCrossover scross; // sexual crossover to use GAGenome::AsexualCrossover across; // asexual crossover to use }; #endif galib247/ga/GABin2DecGenome.C0100644003643600364360000002134210573535473014710 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- bin2dec.C mbwall 19apr95 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved DESCRIPTION: Source file for the binary-to-decimal genome. This is the phenotype for converting binary strings to decimal values. There are limits to the size of the numbers you can use (ie you're limited to the number of bits that can represent a float - see the converters file for more information). ---------------------------------------------------------------------------- */ #include #include #include #include #include #include /* ---------------------------------------------------------------------------- Phenotype class definitions ---------------------------------------------------------------------------- */ #define GA_B2D_CHUNKSIZE 20 GABin2DecPhenotypeCore::GABin2DecPhenotypeCore() : csz(GA_B2D_CHUNKSIZE), n(0), N(0), sz(0) { nbits = oset = 0; minval = maxval = 0; cnt = 1; } GABin2DecPhenotypeCore:: GABin2DecPhenotypeCore(const GABin2DecPhenotypeCore& p) : csz(p.csz), n(p.n), N(p.N), sz(p.sz) { nbits = new unsigned short[N]; oset = new unsigned short[N]; minval = new float[N]; maxval = new float[N]; memcpy(nbits, p.nbits, n*sizeof(unsigned short)); memcpy(oset, p.oset, n*sizeof(unsigned short)); memcpy(minval, p.minval, n*sizeof(float)); memcpy(maxval, p.maxval, n*sizeof(float)); cnt = 1; } GABin2DecPhenotypeCore::~GABin2DecPhenotypeCore(){ if(cnt > 0) GAErr(GA_LOC, "GABin2DecPhenotypeCore", "destructor", gaErrRefsRemain); delete [] nbits; delete [] oset; delete [] minval; delete [] maxval; } GABin2DecPhenotypeCore& GABin2DecPhenotypeCore::operator=(const GABin2DecPhenotypeCore& p){ if(&p == this) return *this; delete [] nbits; delete [] oset; delete [] minval; delete [] maxval; n = p.n; sz = p.sz; N = p.N; csz = p.csz; nbits = new unsigned short[N]; oset = new unsigned short[N]; minval = new float[N]; maxval = new float[N]; memcpy(nbits, p.nbits, n*sizeof(unsigned short)); memcpy(oset, p.oset, n*sizeof(unsigned short)); memcpy(minval, p.minval, n*sizeof(float)); memcpy(maxval, p.maxval, n*sizeof(float)); return *this; } // Add another phenotype to this phenotype object. If needed, we allocate more // space, otherwise just tag the new on then end. We allocate space in chunks // so we don't spend too much time doing memory allocation stuff. void GABin2DecPhenotype::add(unsigned int nb, float min, float max){ if(core->n + 1 > core->N){ core->N += core->csz; unsigned short *nbtmp = core->nbits; core->nbits = new unsigned short[core->N]; memcpy(core->nbits, nbtmp, core->n*sizeof(unsigned short)); delete [] nbtmp; unsigned short *ostmp = core->oset; core->oset = new unsigned short[core->N]; memcpy(core->oset, ostmp, core->n*sizeof(unsigned short)); delete [] ostmp; float *mintmp = core->minval; core->minval = new float[core->N]; memcpy(core->minval, mintmp, core->n*sizeof(float)); delete [] mintmp; float *maxtmp = core->maxval; core->maxval = new float[core->N]; memcpy(core->maxval, maxtmp, core->n*sizeof(float)); delete [] maxtmp; } core->nbits[core->n] = nb; if(core->n > 0) core->oset[core->n] = core->oset[core->n-1] + core->nbits[core->n-1]; else core->oset[core->n] = 0; core->minval[core->n] = min; core->maxval[core->n] = max; core->n++; core->sz += nb; } void GABin2DecPhenotype::remove(unsigned int x){ if(x >= core->n) return; memmove(&(core->nbits[x]), &(core->nbits[x+1]), (core->n - x - 1)*sizeof(unsigned short)); memmove(&(core->oset[x]), &(core->oset[x+1]), (core->n - x - 1)*sizeof(unsigned short)); memmove(&(core->minval[x]), &(core->minval[x+1]), (core->n - x - 1)*sizeof(float)); memmove(&(core->maxval[x]), &(core->maxval[x+1]), (core->n - x - 1)*sizeof(float)); core->n -= 1; } int GABin2DecPhenotype::equal(const GABin2DecPhenotype & b) const { if(core->sz != b.core->sz || core->n != b.core->n) return gaFalse; if(memcmp(core->nbits,b.core->nbits,core->n*sizeof(unsigned short))!=0 || memcmp(core->oset, b.core->oset, core->n*sizeof(unsigned short))!=0 || memcmp(core->minval, b.core->minval, core->n*sizeof(float)) != 0 || memcmp(core->maxval, b.core->maxval, core->n*sizeof(float))) return gaFalse; return(gaTrue); } /* ---------------------------------------------------------------------------- Genome class definition ---------------------------------------------------------------------------- */ void GABin2DecGenome::copy(const GAGenome & orig) { if(&orig == this) return; const GABin2DecGenome* c = DYN_CAST(const GABin2DecGenome*, &orig); if(c) { GA1DBinaryStringGenome::copy(*c); encode = c->encode; decode = c->decode; if(ptype) *ptype = *(c->ptype); else ptype = new GABin2DecPhenotype(*(c->ptype)); } } // We shouldn't have to worry about our superclass's data members for the // attributes part here, but there is no 'copy attributes' function, so we // end up doing it. bummer. GAGenome * GABin2DecGenome::clone(GAGenome::CloneMethod flag) const { GABin2DecGenome *cpy = new GABin2DecGenome(*ptype); if(flag == CONTENTS){ cpy->copy(*this); } else{ cpy->GAGenome::copy(*this); cpy->maxX = maxX; cpy->minX = minX; *(cpy->ptype) = *ptype; cpy->encode = encode; cpy->decode = decode; } return cpy; } // The phenotype does reference counting, so its ok to keep our own copy of // the phenotype. So all we have to do here is copy the one that is passed // to us, then modify the bit string to accomodate the new mapping. const GABin2DecPhenotype & GABin2DecGenome::phenotypes(const GABin2DecPhenotype & p) { *ptype = p; GA1DBinaryStringGenome::resize(p.size()); return *ptype; } // We access the data string directly here. This could be dangerous (if the // bitstream ever changes on us it will affect the way this method sees the // data string). // Eventually we may need to cache the decimal values in an array of floats, // but for now we call the converter routine every time each phenotype is // requested. float GABin2DecGenome::phenotype(unsigned int n) const { if(n >= ptype->nPhenotypes()){ GAErr(GA_LOC, className(), "phenotype", gaErrBadPhenotypeID); return(0.0); } float val=0.0; decode(val, &(data[ptype->offset(n)]), ptype->length(n), ptype->min(n), ptype->max(n)); return val; } // Set the bits of the binary string based on the decimal value that is passed // to us. Notice that the number you pass may or may not be set properly. It // depends on the resolution defined in the phenotype. If you didn't define // enough resolution, then there may be no way to represent the number. // We round off to the closest representable value, then return the number // that we actually entered (the rounded value). // *** this is dangerous! we're accessing the superclass' data representation // directly, so if the representation changes to a bit stream, this will break. // If someone tries to set the phenotype beyond the bounds, we post an error // then set the bits to the closer bound. float GABin2DecGenome::phenotype(unsigned int n, float val) { if(n >= ptype->nPhenotypes()){ GAErr(GA_LOC, className(), "phenotype", gaErrBadPhenotypeID); return val; } if(val < ptype->min(n) || val > ptype->max(n)){ GAErr(GA_LOC, className(), "phenotype", gaErrBadPhenotypeValue); val = ((val < ptype->min(n)) ? ptype->min(n) : ptype->max(n)); } encode(val, &(data[ptype->offset(n)]), ptype->length(n), ptype->min(n), ptype->max(n)); return val; } #ifdef GALIB_USE_STREAMS // Read the incoming data as a list of phenotype values. It would be nice to // do this either as binary or decimal read, but oh well... not much need. int GABin2DecGenome::read(STD_ISTREAM & is) { float value; for(unsigned int i=0; i> value; if(is.fail() || is.eof()) return 1; phenotype(i, value); } return 0; } int GABin2DecGenome::write(STD_OSTREAM & os) const { for(unsigned int i=0; i #include #ifdef max #undef max #endif #ifdef min #undef min #endif class GABin2DecPhenotypeCore { public: GABin2DecPhenotypeCore(); GABin2DecPhenotypeCore(const GABin2DecPhenotypeCore&); virtual ~GABin2DecPhenotypeCore(); GABin2DecPhenotypeCore& operator=(const GABin2DecPhenotypeCore&); unsigned int cnt; // how many references to us? unsigned int csz; // how big are the chunks we allocate? unsigned int n, N; // how many phenotypes do we have? (real,alloc) unsigned short *nbits; // number of bits that max/min get mapped into unsigned short *oset; // offset of the nth gene float *minval, *maxval; // min, max value of phenotype elem unsigned int sz; // total number of bits required }; class GABin2DecPhenotype { public: GABin2DecPhenotype() : core(new GABin2DecPhenotypeCore) {} GABin2DecPhenotype(const GABin2DecPhenotype& p) : core(new GABin2DecPhenotypeCore(*(p.core))) {} virtual ~GABin2DecPhenotype(){core->cnt -= 1; if(core->cnt==0){delete core;}} GABin2DecPhenotype & operator=(const GABin2DecPhenotype& p){ if(&p != this) *core = *(p.core); return *this; } GABin2DecPhenotype * clone() const {return new GABin2DecPhenotype(*this);} void link(GABin2DecPhenotype& p){ core->cnt -= 1; if(core->cnt == 0) delete core; core=p.core; core->cnt += 1; } void add(unsigned int nbits, float min, float max); void remove(unsigned int which); unsigned int size() const {return core->sz;} unsigned int nPhenotypes() const {return core->n;} float min(int which) const {return core->minval[which];} float max(int which) const {return core->maxval[which];} int length(int which) const {return core->nbits[which];} int offset(int which) const {return core->oset[which];} int equal(const GABin2DecPhenotype&) const; protected: GABin2DecPhenotypeCore *core; }; inline int operator==(const GABin2DecPhenotype& a, const GABin2DecPhenotype& b) { return a.equal(b); } inline int operator!=(const GABin2DecPhenotype& a, const GABin2DecPhenotype& b) { return (a.equal(b) ? 0 : 1); } /* ---------------------------------------------------------------------------- The phenotype does reference counting, so we can make a copy of it for our own use and we don't have to worry about extra overhead. ---------------------------------------------------------------------------- */ class GABin2DecGenome : public GA1DBinaryStringGenome { public: GADefineIdentity("GABin2DecGenome", GAID::Bin2DecGenome); public: GABin2DecGenome(const GABin2DecPhenotype & p, GAGenome::Evaluator f=(GAGenome::Evaluator)0, void * u=(void *)0) : GA1DBinaryStringGenome(p.size(), f, u), ptype(new GABin2DecPhenotype(p)){ comparator(DEFAULT_BIN2DEC_COMPARATOR); encoder(DEFAULT_BIN2DEC_ENCODER); decoder(DEFAULT_BIN2DEC_DECODER); } GABin2DecGenome(const GABin2DecGenome & orig) : GA1DBinaryStringGenome(orig.sz) {ptype=(GABin2DecPhenotype *)0; copy(orig);} GABin2DecGenome& operator=(const GAGenome& arg) {copy(arg); return *this;} virtual ~GABin2DecGenome(){delete ptype;} virtual GAGenome *clone(GAGenome::CloneMethod flag=CONTENTS) const ; virtual void copy(const GAGenome &); #ifdef GALIB_USE_STREAMS virtual int read (STD_ISTREAM &); virtual int write (STD_OSTREAM &) const; #endif virtual int equal(const GAGenome &) const; virtual int notequal(const GAGenome &) const; const GABin2DecPhenotype & phenotypes(const GABin2DecPhenotype & p); const GABin2DecPhenotype & phenotypes() const {return *ptype;} int nPhenotypes() const {return ptype->nPhenotypes();} float phenotype(unsigned int n, float val); float phenotype(unsigned int n) const; void encoder(GABinaryEncoder e){encode = e; _evaluated = gaFalse;} void decoder(GABinaryDecoder d){decode = d; _evaluated = gaFalse;} protected: GABin2DecPhenotype * ptype; GABinaryEncoder encode; // function we use to encode the bits GABinaryDecoder decode; // function we use to decode the bits }; #endif galib247/ga/gabincvt.C0100644003643600364360000002444410573535474013743 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- bincvt.C mbwall 29jun95 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved DESCRIPTION: Binary-to-decimal converters. ---------------------------------------------------------------------------- */ #include #include #include #include #include #include // These numbers are machine-specific and are a function of the word length of // the OS you are running. The binary string cannot be too long or else we // can't represent it. And we don't do any special multi-word handling, so we // limit the number of bits that our converters can work on. #ifndef BITBASE #define BITBASE long int #endif // Define the number of bits based on the builtin type #define _GA_MAX_BITS (int)(GALIB_BITS_IN_WORD*sizeof(GALIB_BITBASE)) // These are publicly available, but we don't want to advertise them. They are // mostly just for testing purposes. These are unscaled versions of the // converter routines. int GABinaryEncode(unsigned BITBASE, GABit* bits, unsigned int); int GABinaryDecode(float&, const GABit* bits, unsigned int); // If you write your own encoder/decoder you may want to use these to verify // the parameters. int GACheckEncoding(float&,unsigned int&,float,float,unsigned BITBASE &); int GACheckDecoding(unsigned int&); // This stuff is private. extern char _gaerrbuf1[]; extern char _gaerrbuf2[]; static int _GAEncodeBase(unsigned int, unsigned BITBASE, GABit *, int, int); /* ---------------------------------------------------------------------------- Utilities to check the values for proper sizes. ---------------------------------------------------------------------------- */ int GACheckDecoding(unsigned int& nbits) { if((int)nbits >= _GA_MAX_BITS){ sprintf(_gaerrbuf1,"string is %d bits, max is %d", nbits, _GA_MAX_BITS-1); GAErr(GA_LOC, "GACheckDecoding", gaErrBinStrTooLong, _gaerrbuf1); nbits = _GA_MAX_BITS-1; return 1; } return 0; } int GACheckEncoding(float& val, unsigned int& nbits, float minval, float maxval, unsigned BITBASE & nintervals) { int status = 0; if((int)nbits >= _GA_MAX_BITS){ sprintf(_gaerrbuf1,"string is %d bits, max is %d", nbits, _GA_MAX_BITS-1); GAErr(GA_LOC, "GACheckEncoding", gaErrBinStrTooLong, _gaerrbuf1); nbits = _GA_MAX_BITS-1; status = 1; } nintervals = 1; // this type limits the number of bits we can do nintervals <<= nbits; nintervals--; double interval = (maxval-minval)/(double)nintervals; double actual = (val-minval)/interval; // how many intervals we need nintervals = (unsigned BITBASE)actual; // make it an integer actual = minval+(double)nintervals*interval; // get value we can represent if(actual != val){ sprintf(_gaerrbuf1,"desired: %f\tactual: %f\tdiscretization: %f", val, actual, interval); sprintf(_gaerrbuf2," nbits: %d\t\tmin: %f\t\tmax: %f", nbits, minval, maxval); GAErr(GA_LOC, "GACheckEncoding", gaErrDataLost, _gaerrbuf1, _gaerrbuf2); val = (float)actual; status = 1; } return status; } /* ---------------------------------------------------------------------------- Utility routine to encode bits of a decimal number. This routine recursively loops through the decimal value and grabs the remainder (modulo the base) and sticks the result into each 'bit' (if base is 2 then they're bits, otherwise they're the equivalent for whatever base you're doing). This will only do unsigned integers. ---------------------------------------------------------------------------- */ static int _GAEncodeBase(unsigned int base, unsigned BITBASE val, GABit * binstr, int n, int c) { int status = 0; if(c < 0) return 1; // if this happens we should post an error // it means we didn't get a perfect encoding unsigned BITBASE modval = val % base; binstr[c] = STA_CAST(GABit,modval); // the case is ok since module is small unsigned BITBASE quotient = val / base; if(quotient) status = _GAEncodeBase(base, quotient, binstr, n, c-1); return status; } /* ---------------------------------------------------------------------------- Convert the string of bits into a decimal value. This routine does no scaling - the result that it generates will be a power of two. You must specify a number of bits so that we know how many bits to consider. If you specify too many bits, then we reset to the max we can handle and do the conversion using those bits. We return 1 if there was a problem, otherwise 0. ---------------------------------------------------------------------------- */ int GABinaryDecode(float& result, const GABit* bits, unsigned int nbits) { if(bits == (GABit *)0 || nbits == 0){ result = 0.0; return 1; } int status = GACheckDecoding(nbits); unsigned BITBASE maxint=1; float sum=0.0; for(int i=nbits-1; i>(-1); i--){ // most significant bit first // for(int i=0; i(-1); i--){ // 0th bit is most significant // for(int i=0; i>j); unsigned BITBASE maxint = 1<>1); for(unsigned int i=0; i // The encoder converts a decimal value into a binary string. The decoder // converts a string of bits into a decimal value. Both types of functions // return an error code to indicate whether or not the conversion was // successful. The caller must make sure that sufficient space is available // for the arguments. The encoder will set the value to whatever it was able // to encode, so be sure to check the return status and make your value such // that you can check it if you get a non-zero return code. typedef int (*GABinaryEncoder)(float& value, GABit* bits, unsigned int nbits, float min, float max); typedef int (*GABinaryDecoder)(float& value, const GABit* bits, unsigned int nbits, float min, float max); int GABinaryEncode(float&, GABit* bits, unsigned int, float, float); int GABinaryDecode(float&, const GABit* bits, unsigned int, float, float); int GAGrayEncode(float&, GABit* bits, unsigned int, float, float); int GAGrayDecode(float&, const GABit* bits, unsigned int, float, float); #endif galib247/ga/GABinStr.C0100644003643600364360000000365010573535473013552 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- binstr.C mbwall 30jun95 Copyright (c) 1995 Massachusetts Institute of Technology DESCRIPTION: Source file for the binary string genome. ---------------------------------------------------------------------------- */ #include #include #include #include #include /* ---------------------------------------------------------------------------- BinaryStringGenome ---------------------------------------------------------------------------- */ // Copy the contents of the bitstream. We don't care what format it is in - // we resize to make sure we have adequate space then we just copy all of the // data. // If the original is actually this, then we don't do anything. If the // original is not the same class as this, then we post an error and return. void GABinaryString::copy(const GABinaryString& orig) { if(&orig == this) return; resize(orig.sz); memcpy(data, orig.data, SZ*sizeof(GABit)); } // Resize the bitstream to the specified number of bits. We return the number // of bits actually allocated. For now there is no error checking or memory // management - we assume that we'll always get all of the memory we ask for. // If we resize, we copy the previous bits into the new space. The memory // will never overlap (new should see to that) so we use memcpy not memmove. // If we're making more space, we set the contents of the new space to zeros. int GABinaryString::resize(unsigned int x) { if(sz == x) return sz; if(SZ < x){ while(SZ < x) SZ += csz; if(!data){ data = new GABit [SZ]; memset(data, 0, SZ*sizeof(GABit)); } else{ GABit * tmp = data; data = new GABit [SZ]; memcpy(data, tmp, sz * sizeof(GABit)); memset(&(data[sz]), 0, (SZ-sz)*sizeof(GABit)); delete [] tmp; } } return(sz = x); } galib247/ga/GABinStr.h0100644003643600364360000000476210573535473013624 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- binstr.h mbwall 30jun95 Copyright (c) 1995 Massachusetts Institute of Technology DESCRIPTION: This header defines the interface for the binary string. This is a crude version of a real bitstring object. We don't do real bitstring in the interest of speed and ease of coding this mess up. TO DO: we can get major improvements to speed by inlining functions and getting rid of the error checking... for example, inlining genome and removing the conditional makes it go from 7.5 seconds to 3.2 seconds (bm bl cs 1024 c 0.9) ---------------------------------------------------------------------------- */ #ifndef _ga_binstr_h_ #define _ga_binstr_h_ #include #include #include #define GA_BINSTR_CHUNKSIZE 32 // size of the chunks of bits we allocate class GABinaryString { public: GABinaryString(unsigned int s){ csz=GA_BINSTR_CHUNKSIZE; sz=0; SZ=0; data=(GABit *)0; resize(s); } GABinaryString(const GABinaryString& orig){ sz=0; SZ=0; data=(GABit *)0; copy(orig); } virtual ~GABinaryString(){delete [] data;} void copy(const GABinaryString&); int resize(unsigned int); // pass desired size, in bits int size() const {return sz;} short bit(unsigned int a) const { return(data[a]); } short bit(unsigned int a, short val) { // set/unset the bit return(data[a] = (val ? 1 : 0)); } int equal(const GABinaryString & b, unsigned int r, unsigned int x, unsigned int l) const { return(memcmp(&(data[r]),&(b.data[x]),l*sizeof(GABit))?0:1); } void copy(const GABinaryString & orig, unsigned int r, unsigned int x, unsigned int l){ memcpy(&(data[r]), &(orig.data[x]), l*sizeof(GABit)); } void move(unsigned int r, unsigned int x, unsigned int l){ memmove(&(data[r]), &(data[x]), l*sizeof(GABit)); } void set(unsigned int a, unsigned int l){ memset(&(data[a]), 1, l*sizeof(GABit)); } void unset(unsigned int a, unsigned int l){ memset(&(data[a]), 0, l*sizeof(GABit)); } void randomize(unsigned int a, unsigned int l){ for(unsigned int i=0; i) while others have new-school headers (e.g. ). The default is to use ANSI headers. If you are using an older compiler, make sure this variable is not defined. GALIB_USE_NAMED_TEMPLATES GALIB_USE_EMPTY_TEMPLATES GALIB_USE_COMP_OPERATOR_TEMPLATES Some older compilers do not require strict, ansi template definitions. And some compilers require slightly different ways of specifying templates. And to make it even more complicated, some depend very much on the type of instantiation method that is defined. Sigh. GALIB_USE_STD_NAMESPACE Some platforms need to explicitly use the std namespace when referring to streams and other std components, but others do not. GALIB_USE_STREAMS For systems/environments in which streams are not desired and/or required. If this is not defined, it turns off errors and all of the read/write routines for the classes. GALIB_USE_RTTI If your compiler supports RTTI, or if you turn on the RTTI abilities of your compiler, then define this macro. Without RTTI, if improper casts are made, things will die horribly rather than dropping out in an RTTI-induced exception. GALIB_USE_PID Define this if the system has a getpid function that returns something sane and useful. GALIB_USE_NO_TEMPLATES For compilers that do not do templates. The only type of genome available when this is defined is binary string and any derived classes. list, tree, and array all use templates. You can still use the template code, but you will have to hack it yourself to make it work. GALIB_USE_BORLAND_INST For compilers that use the Borland instantiation model. These compilers expect all of the template code to be in the header file. The Cfront model, on the other hand, expects source files with names similar to the header files, but all of the template code does not need to be in the header files. When you define this flag, the source file that corresponds to the header file is explicitly included at the end of the header file for all headers that contain templates. GALIB_USE_AUTO_INST For compilers that do not do automatic instantiation (such as g++ version 2.6.8) you will have to force instantiations. When this flag is not defined, GAlib forces an instantiation of all of the template classes that it uses (such as real genome and string genome). GALIB_HAVE_NOT_ASSERT Some platforms do not have assert. So for those platforms we define our own simple version of it. USE_GALIB_AS_LIB For windows shared libraries, one must define whether USE_GALIB_AS_DLL static member data are imported or exported. You define one or the other of these, but not both. The default is USE_GALIB_AS_LIB (if you define neither). COMPILE_GALIB_AS_LIB If you are compiling the dome library, define one of COMPILE_GLAIB_AS_DLL these to indicate the windows exports. The default is USE_GALIB_AS_LIB (if you define neither). GALIB_USE_RAN1 These specify which random number function to use. Only GALIB_USE_RAN2 one of these may be specified. You may have to tweak GALIB_USE_RAN3 random.h a bit as well (these functions are not defined GALIB_USE_RAND the same way on each platform). For best results, use GALIB_USE_RANDOM ran2 or ran3 (performance is slightly slower than most GALIB_USE_RAND48 system RNGs, but you'll get better results). If you want to use another random number generator you must hack random.h directly (see the comments in that file). GALIB_BITBASE The built-in type to use for bit conversions. This should be set to the type of the largest integer that your system supports. If you have long long int then use it. If you don't plan to use more than 16 or 32 bits to represent your binary-to-decimal mappings then you can use something smaller (long int for example). If you do not set this, GAlib will automatically use the size of a long int. The bitbase determines the maximum number of bits you can use to represent a decimal number in the binary-to-decimal genomes. GALIB_BITS_IN_WORD How many bits are in a word? For many systems, a word is a char and is 8 bits long. ---------------------------------------------------------------------------- */ // This is a bare-bones os-cpu-compiler detection with no dependencies on any // other header files or macros. We try to detect everything based on what we // will get by default from the compilers. The result of this is three macros // GALIB_OS // GALIB_CPU // GALIB_COMPILER // determine the operating system #if defined(__linux__) #define GALIB_OS "linux" #elif defined(__sgi) #define GALIB_OS "irix" #elif defined(WIN32) #define GALIB_OS "win32" #elif defined(sun) #define GALIB_OS "solaris" #elif defined(__APPLE__) && defined(__MACH__) && defined(__ppc__) #define GALIB_OS "macosx" #elif defined(macintosh) #define GALIB_OS "macos" #elif defined(HPUX10) #define GALIB_OS "hpux10" #elif defined(HPUX11) #define GALIB_OS "hpux11" #elif defined(_AIX) || defined(AIX) #define GALIB_OS "aix" #else #define GALIB_OS "unknown" #endif // determine the cpu #if defined(__INTEL__) || defined(__i386__) || \ defined(__x86__) || defined(_M_IX86) #define GALIB_CPU "i386" #elif defined(__POWERPC__) || defined(__PPC__) || \ defined(__powerpc__) || defined(__ppc__) || \ defined(_POWER) #define GALIB_CPU "ppc" #elif defined(__m68k__) #define GALIB_CPU "68k" #elif defined(__sgi) #define GALIB_CPU "mips" #elif defined(sparc) || defined(__sparc__) #define GALIB_CPU "sparc" #elif defined(__HP_aCC) #define GALIB_CPU "hppa" #else #define GALIB_CPU "unknown" #endif // determine the compiler #if defined(__GNUG__) || defined(__GNUC__) #if __GNUC__ == 4 #define GALIB_COMPILER "gcc4" #elif __GNUC__ == 3 #define GALIB_COMPILER "gcc3" #elif __GNUC__ == 2 #define GALIB_COMPILER "gcc2" #else #define GALIB_COMPILER "gcc" #endif #elif defined(__BORLANDC__) #if __BORLANDC__ < 0x500 #define GALIB_COMPILER "bcc4" #elif __BORLANDC__ < 0x530 #define GALIB_COMPILER "bcc52" #elif __BORLANDC__ < 0x540 #define GALIB_COMPILER "bcc53" #elif __BORLANDC__ < 0x550 #define GALIB_COMPILER "bcc54" #elif __BORLANDC__ < 0x560 #define GALIB_COMPILER "bcc55" #else #define GALIB_COMPILER "bcc" #endif #elif defined(__WATCOMC__) #define GALIB_COMPILER "watcom" #elif defined(_MIPS_SIM) #define GALIB_COMPILER "mipscc" #elif defined(__MWERKS__) #define GALIB_COMPILER "mwerks" #elif defined(_MSC_VER) #if _MSC_VER == 1300 #define GALIB_COMPILER "vcpp7" #elif _MSC_VER == 1200 #define GALIB_COMPILER "vcpp6" #else #define GALIB_COMPILER "vcpp" #endif #elif defined(__HP_aCC) #define GALIB_COMPILER "acc" #elif defined(__IBMCPP__) #define GALIB_COMPILER "xlc" #else #define GALIB_COMPILER "unknown" #endif // ---------------------------------------------------------------------------- // Here are the defines needed for some of the compilers/OSes on which I have // been able to test the GA library. You may have to remove and/or modify // these to get things to work on your system. // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- // Metrowerks' Codewarrior for MacOS, PalmOS, or Win32 (I have not tested CW // on other platforms yet). #if defined(__MWERKS__) #define GALIB_USE_STREAMS #define GALIB_USE_BORLAND_INST #define GALIB_USE_AUTO_INST #if __option(RTTI) #define GALIB_USE_RTTI #endif // ---------------------------------------------------------------------------- // Symantec C++ for mac. This compiler does not handle templates very well, // so if you want to use any of the template components of GAlib then you will // probably have to do some hacking to get things to work. #elif defined(__SC__) #define GALIB_USE_STREAMS #define GALIB_USE_BORLAND_INST // ---------------------------------------------------------------------------- // THINK for mac #elif defined(THINK_C) #define GALIB_USE_STREAMS #define GALIB_USE_BORLAND_INST #define GALIB_USE_COMP_OPERATOR_TEMPLATES // ---------------------------------------------------------------------------- // borland c++ compiler // // You may or may not need the BORLAND_INST flag defined when you use a borland // compiler. I did not need it when I compiled using version 4.0, but I did // need it when I compiled with an earlier version (I think it was 3.x but I // do not remember for certain). // Note that the default random number generator when using a borland (or // any PC compiler, for that matter) is the basic system's RNG. // I did this because of the hassles of 16- vs 32-bit DOS/Windows rubbish. If // you want a better RNG, you can use the others in GAlib, but you'll have to // do a bit of checking to make sure it works with your DOS/Windows config. // All of the RNGs work fine under all of the 32-bit OSes I've tried, but they // don't do so well in a 16-bit OS. // Use the randtest example to check GAlib's RNG after you compile everything. #elif defined(__BORLANDC__) //#define GALIB_USE_RAND // comment this if you're using a 32-bit OS #define GALIB_USE_RTTI #define GALIB_USE_BORLAND_INST #define GALIB_USE_STREAMS //#define GALIB_USE_PID #define GALIB_USE_EMPTY_TEMPLATES //#define GALIB_USE_ANSI_HEADERS //#define GALIB_USE_STD_NAMESPACE //#define GALIB_USE_COMP_OPERATOR_TEMPLATES //#pragma warning (disable : 8027) // switch statements are not inlined //#pragma warning (disable : 8004) // unused variable warnings are lame // ---------------------------------------------------------------------------- // MicroSoft's Visual C++ programming environment. // // this has been test with: // vcpp6 (12.00.8804) // vcpp6 (12.00.8168) // vcpp7 (13.00.9466) // vcpp7 (13.10.3077) // #elif defined(_MSC_VER) // visual studio uses the borland model of template instantiation. #define GALIB_USE_BORLAND_INST // let visual studio do its own instantations, so by default do not force them. #define GALIB_USE_AUTO_INST // use ansi headers with vcpp7. it is a good idea to use them in vcpp6 as well // but some vcpp6 apps are built with non-ansi headers, in which case you // should build with the non-ansi headers so that you do not cross the streams. #define GALIB_USE_ANSI_HEADERS // beware of using streams in an MFC application. many nasties lurk therein... #define GALIB_USE_STREAMS // we default to using std things in the std namespace, but depending on the // version of vcpp you are using and depending on the libraries with which you // will use GAlib, you might have to turn this one off. #define GALIB_USE_STD_NAMESPACE // use the pid only on winnt and derivatives. win95/98/ME do not have it. // this requires unistd.h, which you may or may not have (depending on the // way that you installed the compiler). //#define GALIB_USE_PID // GAlib behaves much better in unknown conditions when rtti is enabled, but // you might have to disable it, depending on the linkage and compilation // options you need for other components you are using with GAlib. #if defined(_CPPRTTI) #define GALIB_USE_RTTI #else #undef GALIB_USE_RTTI #endif // there are many warnings from vcpp, many of which we can safely ignore. //#pragma warning (disable : 4244) // int-to-float warnings #pragma warning (disable : 4305) // double-to-float warnings #pragma warning (disable : 4355) // allow us to use this in constructors //#pragma warning (disable : 4250) // dominated multiple inherits // ---------------------------------------------------------------------------- // GNU compiler // // there are some subtle differences in the way the gcc compiler handles // templates from one version to another. the latest versions are much more // strictly adherant to the c++ standards, although you can relax that with // the permissive option. we try to build this library without the use of the // permissive option. // // there are significant changes between the 3.3 and 3.4 releases of gcc. and // of course there are major differences between the 2.x and 3.x versions, but // those affect us mostly with respect to the use of the std libraries. #elif defined(__GNUG__) #define GALIB_USE_RTTI #define GALIB_USE_BORLAND_INST #define GALIB_USE_STREAMS #define GALIB_USE_PID #define GALIB_USE_EMPTY_TEMPLATES #define GALIB_NEED_INSTANTIATION_PREFIX #if __GNUC__ > 2 #define GALIB_USE_ANSI_HEADERS #define GALIB_USE_STD_NAMESPACE #define GALIB_USE_COMP_OPERATOR_TEMPLATES #endif // ---------------------------------------------------------------------------- // irix 5.3 and irix 6.x #elif defined(__sgi) #define GALIB_USE_STREAMS #define GALIB_USE_PID #include #if (_MIPS_SIM == _MIPS_SIM_NABI32) #define GALIB_USE_RTTI #define GALIB_USE_AUTO_INST #define GALIB_USE_BORLAND_INST #elif (_MIPS_SIM == _MIPS_SIM_ABI64) #define GALIB_USE_RTTI #elif (_MIPS_SIM == _MIPS_SIM_ABI32) #define GALIB_USE_AUTO_INST #endif // ---------------------------------------------------------------------------- // IBM visual age c++ compiler #elif defined(__IBMCPP__) // the -qrtti option turns rtti on and off, but i do not know the // corresponding preprocessor directive to sense it. #define GALIB_USE_RTTI #define GALIB_USE_BORLAND_INST #define GALIB_USE_AUTO_INST #define GALIB_USE_ANSI_HEADERS #define GALIB_USE_STREAMS #define GALIB_USE_STD_NAMESPACE #define GALIB_USE_PID #define GALIB_USE_NAMED_TEMPLATES // ---------------------------------------------------------------------------- // HP aCC compiler #elif defined(__HP_aCC) #define GALIB_USE_RTTI #define GALIB_USE_BORLAND_INST #define GALIB_USE_AUTO_INST //#define GALIB_USE_ANSI_HEADERS #define GALIB_USE_STREAMS //#define GALIB_USE_STD_NAMESPACE #define GALIB_USE_PID //#pragma disable warning 829 // do not care about string literal conversions // ---------------------------------------------------------------------------- // This is an unknown/untested platform and/or compiler. The defaults below // might work for you, but then again, they might not. You may have to adjust // the values of the macros until everything works properly. Comment out the // #error directive to allow things to compile properly. #else #error Unknown/untested compiler/operating system! Check these settings! #define GALIB_USE_RTTI #define GALIB_USE_BORLAND_INST #define GALIB_USE_AUTO_INST #define GALIB_USE_ANSI_HEADERS #define GALIB_USE_STREAMS #define GALIB_USE_STD_NAMESPACE #define GALIB_USE_PID #endif // deal with assertions. at some point we might want a proper definition of // assert here for platforms that do not have it. #if defined(GALIB_HAVE_NOT_ASSERT) #include #define assert(x) \ { \ if(! (x)) { \ fprintf(stderr, "assertion failed at line %d in file %s\n", \ __LINE__, __FILE__); \ exit(1); \ } \ } #else #include #endif // some compilers use one syntax, others use a different syntax. #if defined(GALIB_NEED_INSTANTIATION_PREFIX) #define GALIB_INSTANTIATION_PREFIX template class #else #define GALIB_INSTANTIATION_PREFIX #endif // If no RNG has been selected, use the ran2 generator by default #if !defined(GALIB_USE_RAND) && \ !defined(GALIB_USE_RANDOM) && \ !defined(GALIB_USE_RAND48) && \ !defined(GALIB_USE_RAN2) && \ !defined(GALIB_USE_RAN3) #define GALIB_USE_RAN2 #endif // This defines how many bits are in a single word on your system. Most // systems have a word length of 8 bits. #ifndef GALIB_BITS_IN_WORD #define GALIB_BITS_IN_WORD 8 #endif // Use this to set the maximum number of bits that can be used in binary-to- // decimal conversions. You should make this type the largest integer type // that your system supports. #ifndef GALIB_BITBASE #define GALIB_BITBASE long int #endif // If the system/compiler understands C++ casts, then we use them. Otherwise // we default to the C-style casts. The macros make explicit the fact that we // are doing casts. #if defined(GALIB_USE_RTTI) #define DYN_CAST(type,x) (dynamic_cast(x)) #define CON_CAST(type,x) (const_cast(x)) #define STA_CAST(type,x) (static_cast(x)) #define REI_CAST(type,x) (reinterpret_cast(x)) #else #define DYN_CAST(type,x) ((type)(x)) #define CON_CAST(type,x) ((type)(x)) #define STA_CAST(type,x) ((type)(x)) #define REI_CAST(type,x) ((type)(x)) #endif // Windows is brain-dead about how to export things, so we do this to keep the // code (somewhat) cleaner but still accomodate windows' stupidity. #if defined(COMPILE_GALIB_AS_DLL) #define GA_DLLDECL __declspec(dllexport) #elif defined(USE_GALIB_AS_DLL) #define GA_DLLDECL __declspec(dllimport) #else #define GA_DLLDECL #endif /* ---------------------------------------------------------------------------- DEFAULT OPERATORS These directives determine which operators will be used by default for each of the objects in GAlib. ---------------------------------------------------------------------------- */ // scaling schemes #define USE_LINEAR_SCALING 1 #define USE_SIGMA_TRUNC_SCALING 1 #define USE_POWER_LAW_SCALING 1 #define USE_SHARING 1 // selection schemes #define USE_RANK_SELECTOR 1 #define USE_ROULETTE_SELECTOR 1 #define USE_TOURNAMENT_SELECTOR 1 #define USE_DS_SELECTOR 1 #define USE_SRS_SELECTOR 1 #define USE_UNIFORM_SELECTOR 1 // These are the compiled-in defaults for various genomes and GA objects #define DEFAULT_SCALING GALinearScaling #define DEFAULT_SELECTOR GARouletteWheelSelector #define DEFAULT_TERMINATOR TerminateUponGeneration #define DEFAULT_1DBINSTR_INITIALIZER UniformInitializer #define DEFAULT_1DBINSTR_MUTATOR FlipMutator #define DEFAULT_1DBINSTR_COMPARATOR BitComparator #define DEFAULT_1DBINSTR_CROSSOVER OnePointCrossover #define DEFAULT_2DBINSTR_INITIALIZER UniformInitializer #define DEFAULT_2DBINSTR_MUTATOR FlipMutator #define DEFAULT_2DBINSTR_COMPARATOR BitComparator #define DEFAULT_2DBINSTR_CROSSOVER OnePointCrossover #define DEFAULT_3DBINSTR_INITIALIZER UniformInitializer #define DEFAULT_3DBINSTR_MUTATOR FlipMutator #define DEFAULT_3DBINSTR_COMPARATOR BitComparator #define DEFAULT_3DBINSTR_CROSSOVER OnePointCrossover #define DEFAULT_BIN2DEC_ENCODER GABinaryEncode #define DEFAULT_BIN2DEC_DECODER GABinaryDecode #define DEFAULT_BIN2DEC_COMPARATOR BitComparator #define DEFAULT_1DARRAY_INITIALIZER NoInitializer #define DEFAULT_1DARRAY_MUTATOR SwapMutator #define DEFAULT_1DARRAY_COMPARATOR ElementComparator #define DEFAULT_1DARRAY_CROSSOVER OnePointCrossover #define DEFAULT_2DARRAY_INITIALIZER NoInitializer #define DEFAULT_2DARRAY_MUTATOR SwapMutator #define DEFAULT_2DARRAY_COMPARATOR ElementComparator #define DEFAULT_2DARRAY_CROSSOVER OnePointCrossover #define DEFAULT_3DARRAY_INITIALIZER NoInitializer #define DEFAULT_3DARRAY_MUTATOR SwapMutator #define DEFAULT_3DARRAY_COMPARATOR ElementComparator #define DEFAULT_3DARRAY_CROSSOVER OnePointCrossover #define DEFAULT_1DARRAY_ALLELE_INITIALIZER UniformInitializer #define DEFAULT_1DARRAY_ALLELE_MUTATOR FlipMutator #define DEFAULT_1DARRAY_ALLELE_COMPARATOR ElementComparator #define DEFAULT_1DARRAY_ALLELE_CROSSOVER OnePointCrossover #define DEFAULT_2DARRAY_ALLELE_INITIALIZER UniformInitializer #define DEFAULT_2DARRAY_ALLELE_MUTATOR FlipMutator #define DEFAULT_2DARRAY_ALLELE_COMPARATOR ElementComparator #define DEFAULT_2DARRAY_ALLELE_CROSSOVER OnePointCrossover #define DEFAULT_3DARRAY_ALLELE_INITIALIZER UniformInitializer #define DEFAULT_3DARRAY_ALLELE_MUTATOR FlipMutator #define DEFAULT_3DARRAY_ALLELE_COMPARATOR ElementComparator #define DEFAULT_3DARRAY_ALLELE_CROSSOVER OnePointCrossover #define DEFAULT_STRING_INITIALIZER UniformInitializer #define DEFAULT_STRING_MUTATOR FlipMutator #define DEFAULT_STRING_COMPARATOR ElementComparator #define DEFAULT_STRING_CROSSOVER UniformCrossover #define DEFAULT_REAL_INITIALIZER UniformInitializer #define DEFAULT_REAL_MUTATOR GARealGaussianMutator #define DEFAULT_REAL_COMPARATOR ElementComparator #define DEFAULT_REAL_CROSSOVER UniformCrossover #define DEFAULT_TREE_INITIALIZER NoInitializer #define DEFAULT_TREE_MUTATOR SwapSubtreeMutator #define DEFAULT_TREE_COMPARATOR TopologyComparator #define DEFAULT_TREE_CROSSOVER OnePointCrossover #define DEFAULT_LIST_INITIALIZER NoInitializer #define DEFAULT_LIST_MUTATOR SwapMutator #define DEFAULT_LIST_COMPARATOR NodeComparator #define DEFAULT_LIST_CROSSOVER OnePointCrossover #endif galib247/ga/GADCrowdingGA.C0100644003643600364360000000402110573535473014432 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- gadcrowdingga.C mbwall 29mar99 Copyright (c) 1999 Matthew Wall, all rights reserved ---------------------------------------------------------------------------- */ #include "GADCrowdingGA.h" #include "GAList.h" #include "garandom.h" // this assumes that all of the genomes in the population are the same class void GADCrowdingGA::initialize(unsigned int seed) { GARandomSeed(seed); pop->initialize(); pop->evaluate(gaTrue); stats.reset(*pop); if(!scross) GAErr(GA_LOC, className(), "initialize", gaErrNoSexualMating); } void GADCrowdingGA::step() { if(pop->size() == 0) return; GAGenome *child = pop->individual(0).clone(); GAList indpool; for (int i=0; isize(); i++) indpool.insert(i); do { int *ip; indpool.warp(GARandomInt(0,indpool.size()-1)); // select mom ip=indpool.remove(); GAGenome *mom = &pop->individual(*ip); delete ip; indpool.warp(GARandomInt(0,indpool.size()-1)); // select dad ip=indpool.remove(); GAGenome *dad = &pop->individual(*ip); delete ip; stats.numsel += 2; // create child stats.numcro += (*scross)(*mom, *dad, child, 0); stats.nummut += child->mutate(pMutation()); stats.numeval += 1; float d1 = child->compare(*mom); // replace closest parent float d2 = child->compare(*dad); if (d1 < d2) { if (minmax == MINIMIZE) { if (child->score() < mom->score()) { mom->copy(*child); stats.numrep += 1; } } else { if (child->score() > mom->score()) { mom->copy(*child); stats.numrep += 1; } } } else { if (minmax == MINIMIZE) { if (child->score() < dad->score()) { dad->copy(*child); stats.numrep += 1; } } else { if (child->score() > dad->score()) { dad->copy(*child); stats.numrep += 1; } } } } while (indpool.size()>1); pop->evaluate(gaTrue); stats.update(*pop); delete child; } galib247/ga/GADCrowdingGA.h0100644003643600364360000000140610573535473014503 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- dcrowdingga.h mbwall 29mar99 Copyright (c) 1999 Matthew Wall, all rights reserved Header file for the steady-state genetic algorithm class. ---------------------------------------------------------------------------- */ #ifndef _ga_deterministic_crowding_ga_h_ #define _ga_deterministic_crowding_ga_h_ #include class GADCrowdingGA : public GAGeneticAlgorithm { public: GADefineIdentity("GADeterministicCrowdingGA", 241); GADCrowdingGA(const GAGenome& g) : GAGeneticAlgorithm(g) {} virtual ~GADCrowdingGA() {} virtual void initialize(unsigned int seed=0); virtual void step(); GADCrowdingGA& operator++() { step(); return *this; } }; #endif galib247/ga/GADemeGA.C0100644003643600364360000002761510573535474013443 0ustar mwallmwall/* ---------------------------------------------------------------------------- gademe.C mbwall 28jul94 Copyright (c) 1995-1996 Massachusetts Institute of Technology all rights reserved Souce file for the deme-based genetic algorithm object. ---------------------------------------------------------------------------- */ #include #include GAParameterList& GADemeGA::registerDefaultParameters(GAParameterList& p) { GAGeneticAlgorithm::registerDefaultParameters(p); p.add(gaNnPopulations, gaSNnPopulations, GAParameter::INT, &gaDefNPop); p.add(gaNnMigration, gaSNnMigration, GAParameter::INT, &gaDefNMig); return p; } GADemeGA::GADemeGA(const GAGenome& c) : GAGeneticAlgorithm(c) { npop = gaDefNPop; params.add(gaNnPopulations, gaSNnPopulations, GAParameter::INT, &npop); nmig = gaDefNMig; params.add(gaNnMigration, gaSNnMigration, GAParameter::INT, &nmig); unsigned int nr = pop->size()/2; nrepl = new int [npop]; deme = new GAPopulation* [npop]; pstats = new GAStatistics [npop]; tmppop = new GAPopulation(c, nr); for(unsigned int i=0; isize()/2; nrepl = new int [npop]; deme = new GAPopulation* [npop]; pstats = new GAStatistics [npop]; tmppop = new GAPopulation(p.individual(0), nr); for(unsigned int i=0; icopy(*(ga.deme[i])); tmppop->copy(*(ga.tmppop)); pstats = new GAStatistics[npop]; for(i=0; isize(); jj++) deme[ii]->individual(jj).evaluator(f); else for(int jj=0; jjsize(); jj++) deme[i]->individual(jj).evaluator(f); } void GADemeGA::objectiveData(int i, const GAEvalData& v){ if(i == ALL) for(unsigned int ii=0; iisize(); jj++) deme[ii]->individual(jj).evalData(v); else for(int jj=0; jjsize(); jj++) deme[i]->individual(jj).evalData(v); } const GAPopulation& GADemeGA::population(int i, const GAPopulation& p) { if(i == ALL) for(unsigned int ii=0; iisize(value); else deme[i]->size(value); return value; } int GADemeGA::nReplacement(int i, unsigned int value){ if(i == ALL) { for(unsigned int ii=0; ii (unsigned int)deme[ii]->size()) GAErr(GA_LOC, className(), "nReplacement", gaErrBadPRepl); else { params.set(gaNnReplacement, (unsigned int)value); nrepl[ii] = value; } } } else { if(value > (unsigned int)deme[i]->size()) GAErr(GA_LOC, className(), "nReplacement", gaErrBadNRepl); else nrepl[i] = value; } if((unsigned int)(tmppop->size()) < value) { tmppop->size(value); } return value; } GAScalingScheme& GADemeGA::scaling(int i, const GAScalingScheme & s){ if(i == ALL) for(unsigned int ii=0; iiscaling(s); else deme[i]->scaling(s); return deme[((i==ALL) ? 0 : i)]->scaling(); } GASelectionScheme& GADemeGA::selector(int i, const GASelectionScheme& s){ if(i == ALL) for(unsigned int ii=0; iiselector(s); else deme[i]->selector(s); return deme[((i==ALL) ? 0 : i)]->selector(); } int GADemeGA::nMigration(unsigned int n) { params.set(gaNnMigration, (unsigned int)n); return nmig = n; } // change the number of populations. try affect the evolution as little as // possible in the process, so set things to sane values where we can. int GADemeGA::nPopulations(unsigned int n) { if(n < 1 || n == npop) return npop; if(n < npop) { for(unsigned int i=n; isize(npop); return npop; } int GADemeGA::minimaxi(int m) { if(m == MINIMIZE){ tmppop->order(GAPopulation::LOW_IS_BEST); for(unsigned int i=0; iorder(GAPopulation::LOW_IS_BEST); } else{ tmppop->order(GAPopulation::HIGH_IS_BEST); for(unsigned int i=0; iorder(GAPopulation::HIGH_IS_BEST); } return GAGeneticAlgorithm::minimaxi(m); } // We only use the sexual mating, so only check for that one. Initialize each // of the popultions and set stats appropriately. void GADemeGA::initialize(unsigned int seed) { GARandomSeed(seed); for(unsigned int i=0; iinitialize(); deme[i]->evaluate(gaTrue); pstats[i].reset(*deme[i]); pop->individual(i).copy(deme[i]->best()); } pop->touch(); stats.reset(*pop); if(!scross) GAErr(GA_LOC, className(), "initialize", gaErrNoSexualMating); } // To evolve the genetic algorithm, we loop through all of our populations and // evolve each one of them. Then allow the migrator to do its thing. Assumes // that the tmp pop is at least as big as the largest nrepl that we'll use. // The master population maintains the best n individuals from each of the // populations, and it is based on those that we keep the statistics for the // entire genetic algorithm run. void GADemeGA::step() { int i, mut, c1, c2; GAGenome *mom, *dad; float pc; if(!scross) pc = 0.0; else pc = pCrossover(); for(unsigned int ii=0; iiselect()); dad = &(deme[ii]->select()); pstats[ii].numsel += 2; c1 = c2 = 0; if(GAFlipCoin(pc)){ pstats[ii].numcro += (*scross)(*mom, *dad, &tmppop->individual(i), &tmppop->individual(i+1)); c1 = c2 = 1; } else{ tmppop->individual( i ).copy(*mom); tmppop->individual(i+1).copy(*dad); } pstats[ii].nummut += (mut=tmppop->individual( i ).mutate(pMutation())); if(mut > 0) c1 = 1; pstats[ii].nummut += (mut=tmppop->individual(i+1).mutate(pMutation())); if(mut > 0) c2 = 1; pstats[ii].numeval += c1 + c2; } if(nrepl[ii] % 2 != 0){ // do the remaining population member mom = &(deme[ii]->select()); dad = &(deme[ii]->select()); pstats[ii].numsel += 2; c1 = 0; if(GAFlipCoin(pc)){ pstats[ii].numcro += (*scross)(*mom, *dad, &tmppop->individual(i), (GAGenome*)0); c1 = 1; } else{ if(GARandomBit()) tmppop->individual(i).copy(*mom); else tmppop->individual(i).copy(*dad); } pstats[ii].nummut += (mut=tmppop->individual(i).mutate(pMutation())); if(mut > 0) c1 = 1; pstats[ii].numeval += c1; } for(i=0; iadd(&tmppop->individual(i)); deme[ii]->evaluate(); deme[ii]->scale(); for(i=0; ireplace(deme[ii]->remove(GAPopulation::WORST, GAPopulation::SCALED), i); pstats[ii].numrep += nrepl[ii]; } migrate(); for(unsigned int jj=0; jjevaluate(); pstats[jj].update(*deme[jj]); } stats.numsel = stats.numcro = stats.nummut = stats.numrep = stats.numeval=0; for(unsigned int kk=0; kkindividual(kk).copy(deme[kk]->best()); stats.numsel += pstats[kk].numsel; stats.numcro += pstats[kk].numcro; stats.nummut += pstats[kk].nummut; stats.numrep += pstats[kk].numrep; stats.numeval += pstats[kk].numeval; } pop->touch(); stats.update(*pop); for(unsigned int ll=0; llindividual(j)); for(unsigned int i=1; ireplace(ind[j], j); } for(j=0; jreplace(ind[j], j); delete [] ind; } galib247/ga/GADemeGA.h0100644003643600364360000001071110573535473013474 0ustar mwallmwall/* ---------------------------------------------------------------------------- gademe.h mbwall jan96 Copyright (c) 1995-1996 Massachusetts Institute of Technology all rights reserved Header for the deme (parallel population) genetic algorithm class. This genetic algorithm lets you specify a number of individuals to migrate from one population to another at the end of each generation. You can specify how many populations to maintain. Each population evolves using a steady-state genetic algorithm. At the end of each generation, the specified number of individuals migrate from one population to the next (we use the loop migration topology in this implementation). You can modify the migration method by deriving a new class from this one and redefine the migration method. If you want to use a different kind of genetic algorithm for each population then you'll have to modify the mechanics of the step method. ---------------------------------------------------------------------------- */ #ifndef _ga_gademe_h_ #define _ga_gademe_h_ #include class GADemeGA : public GAGeneticAlgorithm { public: GADefineIdentity("GADemeGA", GAID::DemeGA); enum {ALL=(-1)}; static GAParameterList& registerDefaultParameters(GAParameterList&); public: GADemeGA(const GAGenome&); GADemeGA(const GAPopulation&); GADemeGA(const GADemeGA&); GADemeGA& operator=(const GADemeGA&); virtual ~GADemeGA(); virtual void copy(const GAGeneticAlgorithm&); virtual void initialize(unsigned int seed=0); virtual void step(); virtual void migrate(); // new for this derived class GADemeGA & operator++() { step(); return *this; } virtual int setptr(const char* name, const void* value); virtual int get(const char* name, void* value) const; virtual int minimaxi() const {return minmax;} virtual int minimaxi(int m); virtual const GAPopulation& population() const {return *pop;} virtual const GAPopulation& population(const GAPopulation& p) { GAGeneticAlgorithm::population(p); return population(ALL,p); } virtual int populationSize() const {return pop->size();} virtual int populationSize(unsigned int n) { GAGeneticAlgorithm::populationSize(n); return populationSize(ALL,n); } virtual GAScalingScheme& scaling() const {return pop->scaling();} virtual GAScalingScheme& scaling(const GAScalingScheme & s) { GAGeneticAlgorithm::scaling(s); return scaling(ALL,s);} virtual GASelectionScheme& selector() const {return pop->selector(); } virtual GASelectionScheme& selector(const GASelectionScheme& s) { GAGeneticAlgorithm::selector(s); return selector(ALL,s);} virtual void objectiveFunction(GAGenome::Evaluator f) { GAGeneticAlgorithm::objectiveFunction(f); objectiveFunction(ALL,f); } virtual void objectiveData(const GAEvalData& v) { GAGeneticAlgorithm::objectiveData(v); objectiveData(ALL,v); } const GAPopulation& population(unsigned int i) const {return *deme[i];} const GAPopulation& population(int i, const GAPopulation&); int populationSize(unsigned int i) const {return deme[i]->size();} int populationSize(int i, unsigned int n); int nReplacement(unsigned int i) const {return nrepl[i];} int nReplacement(int i, unsigned int n); int nMigration() const {return nmig;} int nMigration(unsigned int i); int nPopulations() const {return npop;} int nPopulations(unsigned int i); GAScalingScheme& scaling(unsigned int i) const {return deme[i]->scaling();} GAScalingScheme& scaling(int i, const GAScalingScheme & s); GASelectionScheme& selector(unsigned int i)const{return deme[i]->selector();} GASelectionScheme& selector(int i, const GASelectionScheme& s); void objectiveFunction(int i, GAGenome::Evaluator f); void objectiveData(int i, const GAEvalData&); const GAStatistics& statistics() const {return stats;} const GAStatistics& statistics(unsigned int i) const {return pstats[i];} protected: unsigned int npop; // how many populations do we have? int *nrepl; // how many to replace each generation GAPopulation** deme; // array of populations that we'll use GAPopulation* tmppop; // temp pop for doing the evolutions GAStatistics* pstats; // statistics for each population unsigned int nmig; // number to migrate from each population }; #ifdef GALIB_USE_STREAMS inline STD_OSTREAM & operator<< (STD_OSTREAM & os, GADemeGA & arg) {arg.write(os); return(os);} inline STD_ISTREAM & operator>> (STD_ISTREAM & is, GADemeGA & arg) {arg.read(is); return(is);} #endif #endif galib247/ga/gaerror.C0100644003643600364360000001206210573535473013577 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- error.C mbwall 28jul94 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved DESCRIPTION: This file contains all of the error messages for the library. ---------------------------------------------------------------------------- */ #include #include #include char gaErrMsg[512]; char _gaerrbuf1[120]; char _gaerrbuf2[120]; #ifdef GALIB_USE_STREAMS static STD_OSTREAM *__gaErrStream = & STD_CERR; #endif static GABoolean __gaErrFlag = gaTrue; static char *__gaErrStr[] = { "error reading from file: ", "error writing to file: ", "unexpected EOF encountered during read.", "bad probability value. Must be between 0.0 and 1.0, inclusive.", "objects are different types.", "this method has not been defined.", "core deleted with references remaining.", "the custom replacement strategy requires a replacement function", "unknown replacement strategy", "number of children must be greater than 0", "replacement percentage must be between 0.0 and 1.0, inclusive", "number of indiv for replacement must be less than pop size", "index of individual is out-of-bounds", "population contains no individuals from which to clone new individuals", "there must be at least one individual in each population", "no sexual crossover has been defined. no mating can occur.", "no asexual crossover has been defined. no mating can occur.", "children must have same resize behaviour for any given dimension", "parents and children must have the same dimensions", "parents must be the same length", "upper limit must be greater than lower limit.", "bad phenotype - ID is out of bounds.", "bad phenotype - value is less than min or greater than max.", "dimensions of bounds set do not match dimensions of the genome", "linear scaling multiplier must be greater than 1.0", "sigma truncation multiplier must be greater than 0.0", "negative objective function score!\n\ all raw objective scores must be positive for linear scaling.", "negative objective function score!\n\ all raw objective scores must be positive for power law scaling.", "the cutoff for triangular sharing must be greater than 0.0", "cannot index an allele in a bounded, non-discretized set of alleles", "length of binary string exceeds maximum for this computer/OS type.", "specified value cannot be exactly represented with these bits.", "bad 'where' indicator", "bogus type, data may be corrupt", "bad links in tree. operation aborted.", "cannot swap a node with its ancestor", "cannot insert this object into itself", "node relative to which insertion is made must be non-NULL.", "root node must have no siblings. insertion aborted.", "cannot insert before a root node (only below).", "cannot insert after a root node (only below)." }; void GAErr(const GASourceLocator loc, const char *clss, const char *func, const char *msg1, const char *msg2, const char *msg3){ gaErrMsg[0] = '\0'; strcat(gaErrMsg, clss); strcat(gaErrMsg, "::"); strcat(gaErrMsg, func); strcat(gaErrMsg, ":\n "); strcat(gaErrMsg, msg1); strcat(gaErrMsg, "\n"); if(msg2){ strcat(gaErrMsg, " "); strcat(gaErrMsg, msg2); strcat(gaErrMsg, "\n"); } if(msg3){ strcat(gaErrMsg, " "); strcat(gaErrMsg, msg3); strcat(gaErrMsg, "\n"); } sprintf(_gaerrbuf1, " %s : %ld\n", loc.file, loc.line); strcat(gaErrMsg, _gaerrbuf1); #ifdef GALIB_USE_STREAMS if(__gaErrFlag == gaTrue) *__gaErrStream << gaErrMsg; #endif } void GAErr(const GASourceLocator loc, const char *clss, const char *func, GAErrorIndex i, const char *msg2, const char *msg3){ gaErrMsg[0] = '\0'; strcat(gaErrMsg, clss); strcat(gaErrMsg, "::"); strcat(gaErrMsg, func); strcat(gaErrMsg, ":\n "); strcat(gaErrMsg, __gaErrStr[i]); strcat(gaErrMsg, "\n"); if(msg2){ strcat(gaErrMsg, " "); strcat(gaErrMsg, msg2); strcat(gaErrMsg, "\n"); } if(msg3){ strcat(gaErrMsg, " "); strcat(gaErrMsg, msg3); strcat(gaErrMsg, "\n"); } sprintf(_gaerrbuf1, " %s : %ld\n", loc.file, loc.line); strcat(gaErrMsg, _gaerrbuf1); #ifdef GALIB_USE_STREAMS if(__gaErrFlag == gaTrue) *__gaErrStream << gaErrMsg; #endif } void GAErr(const GASourceLocator loc, const char *func, GAErrorIndex i, const char *msg2, const char *msg3){ gaErrMsg[0] = '\0'; strcat(gaErrMsg, func); strcat(gaErrMsg, ":\n "); strcat(gaErrMsg, __gaErrStr[i]); strcat(gaErrMsg, "\n"); if(msg2){ strcat(gaErrMsg, " "); strcat(gaErrMsg, msg2); strcat(gaErrMsg, "\n"); } if(msg3){ strcat(gaErrMsg, " "); strcat(gaErrMsg, msg3); strcat(gaErrMsg, "\n"); } sprintf(_gaerrbuf1, " %s : %ld\n", loc.file, loc.line); strcat(gaErrMsg, _gaerrbuf1); #ifdef GALIB_USE_STREAMS if(__gaErrFlag == gaTrue) *__gaErrStream << gaErrMsg; #endif } void GAReportErrors(GABoolean flag){ __gaErrFlag = flag; } #ifdef GALIB_USE_STREAMS void GASetErrorStream(STD_OSTREAM & s){ __gaErrStream = &s; } #endif galib247/ga/gaerror.h0100644003643600364360000000674410573535473013656 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- error.h mbwall 7may95 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved DESCRIPTION: This defines the error routines for handling errors. ---------------------------------------------------------------------------- */ #ifndef _ga_error_h_ #define _ga_error_h_ #include #include #include // This object is for telling us where in the source code an error occurs. class GASourceLocator { public: GASourceLocator(const char* f, long l) : file(f), line(l) {} const char* file; long line; }; #define GA_LOC GASourceLocator(__FILE__, __LINE__) // These are the indices for all of the error messages used in the library. enum GAErrorIndex { // general errors gaErrReadError=0, gaErrWriteError, gaErrUnexpectedEOF, gaErrBadProbValue, gaErrObjectTypeMismatch, gaErrOpUndef, gaErrRefsRemain, // errors for the GA objects gaErrNeedRS, gaErrBadRS, gaErrBadCS, gaErrBadPRepl, gaErrBadNRepl, gaErrBadPopIndex, gaErrNoIndividuals, gaErrBadPopSize, gaErrNoSexualMating, gaErrNoAsexualMating, // errors for the genome and crossover objects gaErrSameBehavReqd, gaErrSameLengthReqd, gaErrBadParentLength, gaErrBadResizeBehaviour, gaErrBadPhenotypeID, gaErrBadPhenotypeValue, gaErrBadBndsDim, // scaling scheme error messages gaErrBadLinearScalingMult, gaErrBadSigmaTruncationMult, gaErrNegFitness, gaErrPowerNegFitness, gaErrBadSharingCutoff, // miscellaneous error messages from various data objects gaErrNoAlleleIndex, gaErrBinStrTooLong, gaErrDataLost, gaErrBadWhereIndicator, gaErrBadTypeIndicator, gaErrBadTreeLinks, gaErrCannotSwapAncestors, gaErrCannotInsertIntoSelf, gaErrCannotInsertOnNilNode, gaErrCannotInsertWithSiblings, gaErrCannotInsertBeforeRoot, gaErrCannotInsertAfterRoot }; // Error messages will look like this: (assuming that you use streams) // // GASimpleGA::function: // this is the error message // /usr/people/jimmyboy/doughhead.C : XXX // // GAGenome::function: // primary error message // additional error messages go here // /usr/people/algore/distribute_your_intelligence.C : XXX // // MyOwnFunction: // primary error message // additional error messages go here // /usr/people/algore/distribute_your_intelligence.C : XXX // void GAErr(const GASourceLocator loc, const char *clss, const char *function_name, GAErrorIndex i, const char *msg2=0, const char *msg3=0); void GAErr(const GASourceLocator loc, const char *clss, const char *function_name, const char *msg1, const char *msg2=0, const char *msg3=0); void GAErr(const GASourceLocator loc, const char *function_name, GAErrorIndex i, const char *msg2=0, const char *msg3=0); // Use this function to turn on/off the error reporting. If you turn off the // error reporting, the messages will still get stuck into the global error // message string, but they will not be sent to the error stream. void GAReportErrors(GABoolean flag); // Provide a mechanism for redirecting the error messages. #ifdef GALIB_USE_STREAMS void GASetErrorStream(STD_OSTREAM &); #else inline void GASetErrorStream(){} // dummy function #endif // This error string contains the text of the most recent error message. If a // GAlib function returns an error code, this string will contain the text of // the explanation for the error. extern char gaErrMsg[]; #endif galib247/ga/GAEvalData.h0100644003643600364360000000150510573535473014074 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- eval.h mbwall 3dec95 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved DESCRIPTION: This is the basic interface for the object that contains evaluation data. It can be used with genomes and/or populations in combination with their respective evaluation methods. ---------------------------------------------------------------------------- */ #ifndef _ga_eval_h_ #define _ga_eval_h_ class GAEvalData { public: GAEvalData() {} GAEvalData(const GAEvalData&) {} virtual ~GAEvalData() {} GAEvalData& operator=(const GAEvalData& orig) { if(&orig != this) copy(orig); return *this; } virtual GAEvalData* clone() const =0; virtual void copy(const GAEvalData&) =0; }; #endif galib247/ga/GAGenome.C0100644003643600364360000000463410573535473013566 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- genome.C mbwall 19apr95 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved DESCRIPTION: Definitions for genome base class. See the header file for complete documentation for deriving new classes. Comments here are implementation- specific details about base class member functions. ---------------------------------------------------------------------------- */ #include // These are the default genome operators. // None does anything - they just post an error message to let you know that no // method has been defined. These are for the base class (which has no // function by itself). void GAGenome::NoInitializer(GAGenome & c){ GAErr(GA_LOC, c.className(), "initializer", gaErrOpUndef); } int GAGenome::NoMutator(GAGenome & c, float){ GAErr(GA_LOC, c.className(), "mutator", gaErrOpUndef); return 0; } float GAGenome::NoComparator(const GAGenome& c, const GAGenome&){ GAErr(GA_LOC, c.className(), "comparator", gaErrOpUndef); return -1.0; } GAGenome:: GAGenome(Initializer i, Mutator m, Comparator c){ if(i==0) i=NoInitializer; if(m==0) m=NoMutator; if(c==0) c=NoComparator; _score=_fitness=0.0; _evaluated=gaFalse; _neval=0; ga=0; ud=0; eval=0; evd=0; init=i; mutr=m; cmp=c; sexcross = 0; asexcross = 0; } GAGenome::GAGenome(const GAGenome & orig){ evd=0; _neval=0; GAGenome::copy(orig); } GAGenome::~GAGenome(){ delete evd; } GAGenome* GAGenome::clone(CloneMethod) const { GAErr(GA_LOC, className(), "clone", gaErrOpUndef); return new GAGenome(*this); } // The eval count is not copied from the other genome - that would inflate the // count. void GAGenome::copy(const GAGenome & orig){ if(&orig == this) return; _score=orig._score; _fitness=orig._fitness; _evaluated=orig._evaluated; ga=orig.ga; ud=orig.ud; eval=orig.eval; init=orig.init; mutr=orig.mutr; cmp=orig.cmp; sexcross=orig.sexcross; asexcross=orig.asexcross; _neval = 0; if(orig.evd){ if(evd) evd->copy(*orig.evd); else evd = orig.evd->clone(); } // don't delete if c doesn't have one } float GAGenome::evaluate(GABoolean flag) const { if(_evaluated == gaFalse || flag == gaTrue){ GAGenome *This = (GAGenome*)this; if(eval){ This->_neval++; This->_score = (*eval)(*This); } This->_evaluated = gaTrue; } return _score; } galib247/ga/GAGenome.h0100644003643600364360000003217610573535474013636 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- genome.h mbwall 28jul94 Copyright (c) 1995 Massachusetts Institute of Technology DESCRIPTION: The base genome class just defines the genome interface - how to mutate, crossover, evaluate, etc. When you create your own genome, multiply inherit from the base genome class and the data type that you want to use. Use the data type to store the information and use the genome part to tell the GA how it should operate on the data. See comments below for further details. ---------------------------------------------------------------------------- */ #ifndef _ga_genome_h_ #define _ga_genome_h_ #include #include #include #include #include class GAGeneticAlgorithm; class GAGenome; /* ---------------------------------------------------------------------------- Genome ------------------------------------------------------------------------------- Deriving your own genomes: For any derived class be sure to define the canonical methods: constructor, copy constructor, operator=, and destructor. Make sure that you check for a self-copy in your copy method (it is possible that a genome will be selected to cross with itself, and self-copying is not out of the question) To work properly with the GAlib, you MUST define the following: YourGenome( -default-args-for-your-genome ) YourGenome(const YourGenome&) virtual ~YourGenome() virtual GAGenome* clone(GAGenome::CloneMethod) virtual copy(const GAGenome&) If your genome class defines any new properties you should to define: virtual int read(istream&) virtual int write(ostream&) const virtual int equal(const GAGenome&) const When you derive a genome, don't forget to use the _evaluated flag to indicate when the state of the genome has changed and an evaluation is needed. Assign a default crossover method so that users don't have to assign one unless they want to. Do this in the constructor. It is a good idea to define an identity for your genome (especially if you will be using it in an environment with multiple genome types running around). Use the DefineIdentity/DeclareIdentity macros (defined in id.h) to do this in your class definition. Brief overview of the member functions: initialize Use this method to set the initial state of your genomes once they have been created. This initialization is for setting up the genome's state, not for doing the basic mechanics of genome class management. The default behaviour of this method is to change randomly the contents of the genome. If you want to bias your initial population, this is where to make that happen. The initializer is used to initialize the genome (duh). Notice that the state of the genome is unknown - memory may or may not have been allocated, and the genome may or may not have been used before. So your initializer should first clean up as needed, then do its thing. The initializer may be called any number of times (unlike a class constructor which is called only once for a given instance). mutate Mutate the genome with probability as specified. What mutation means depends upon the data type of the genome. For example, you could have a bit string in which 50% mutation means each bit has a 50% chance of getting flipped, or you could have a tree in which 50% mutation means each node has a 50% chance of getting deleted, or you could have a bit string in which 50% mutation means 50% of the bits ACTUALLY get flipped. The mutations member returns the number of mutations since the genome was initialized. The mutator makes a change to the genome with likeliehood determined by the mutation rate parameter. The exact meaning of mutation is up to you, as is the specific meaning of the mutation rate. The function returns the number of mutations that actually occurred. crossover Genomes don't really have any clue about other genomes, so we don't make the crossover a member function. Instead, each genome kind of knows how to mate with other genomes to generate offspring, but they are not capable of doing it themselves. The crossover member function is used to set the default mating mode for the genomes - it does not actually perform the crossover. This way the GA can use asexual crossover if it wants to (but genomes only know how to do the default sexual crossover). This also lets you do funky stuff like crossover between different data types and group sex to generate new offspring. We define two types of crossover: sexual and asexual. Most GAlib algorithms use the sexual crossover, but both are available. Each genome knows the preferred crossover method, but none is capable of reproducing. The genetic algorithm must actually perform the mating because it involves another genome (as parent and/or child). evaluator Set the genome's objective function. This also sets marks the evaluated flag to indicate that the genome must be re-evaluated. Evaluation happens on-demand - the objective score is not calculated until it is requested. Then it is cached so that it does not need to be re- calculated each time it is requested. This means that any member function that modifies the state of the genome must also set the evaluated flag to indicate that the score must be recalculated. The genome objective function is used by the GA to evaluate each member of the population. comparator This method is used to determine how similar two genomes are. If you want to use a different comparison method without deriving a new class, then use the comparator function to do so. For example, you may want to do phenotype- based comparisons rather than genotype-based comparisons. In many cases we have to compare two genomes to determine how similar or different they are. In traditional GA literature this type of function is referred to as a 'distance' function, probably because bit strings can be compared using the Hamming distance as a measure of similarity. In GAlib, we define a genome comparator function that does exactly this kind of comparison. If the genomes are identical, the similarity function should return a value of 0.0, if completely different then return a value greater than 0. The specific definition of what "the same" and what "different" mean is up to you. Most of the default comparators use the genotype for the comparison, but you can use the phenotype if you prefer. There is no upper limit to the distance score as far as GAlib is concerned. The no-op function returns a -1 to signify that the comparison failed. evalData The evalData member is useful if you do not want to derive a new genome class but want to store data with each genome. When you clone a genome, the eval data also gets cloned so that each genome has its own eval data (unlike the user data pointer described next which is shared by all genomes). userData The userData member is used to provide all genomes access to the same user data. This can be a pointer to anything you want. Any genome cloned from another will share the same userData as the original. This means that all of the genomes in a population, for example, share the same userData. score Evaluate the 'performance' of the genome using the objective function. The score is kept in the 'score' member. The 'evaluated' member tells us whether or not we can trust the score. Be sure to set/unset the 'evaluated' member as appropriate (eg cross and mutate change the contents of the genome so they unset the 'evaluated' flag). If there is no objective function, then simply return the score. This allows us to use population-based evaluation methods (where the population method sets the score of each genome). clone This method allocates space for a new genome and copies the original into the new space. Depending on the argument, it either copies the entire original or just parts of the original. For some data types, clone contents and clone attributes will do the same thing. If your data type requires significant overhead for initialization, then you'll probably want to distinguish between cloning contents and cloning attributes. clone(cont) Clone the contents of the genome. Returns a pointer to a GAGenome (which actually points to a genome of the type that was cloned). This is a 'deep copy' in which every part of the genome is duplicated. clone(attr) Clone the attributes of the genome. This method does nothing to the contents of the genome. It does NOT call the initialization method. For some data types this is the same thing as cloning the contents. ---------------------------------------------------------------------------- */ class GAGenome : public GAID { public: GADefineIdentity("GAGenome", GAID::Genome); public: typedef float (*Evaluator)(GAGenome &); typedef void (*Initializer)(GAGenome &); typedef int (*Mutator)(GAGenome &, float); typedef float (*Comparator)(const GAGenome&, const GAGenome&); typedef int (*SexualCrossover)(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*); typedef int (*AsexualCrossover)(const GAGenome&, GAGenome*); public: static void NoInitializer(GAGenome &); static int NoMutator(GAGenome &, float); static float NoComparator(const GAGenome&, const GAGenome&); public: enum Dimension {LENGTH = 0, WIDTH = 0, HEIGHT = 1, DEPTH = 2}; enum CloneMethod {CONTENTS = 0, ATTRIBUTES = 1}; enum {FIXED_SIZE = -1, ANY_SIZE = -10}; public: // The GNU compiler sucks. It won't recognize No*** as a member of the genome // class. So we have to use 0 as the defaults then check in the constructor. GAGenome(Initializer i=0, Mutator m=0, Comparator c=0); GAGenome(const GAGenome&); GAGenome & operator=(const GAGenome & arg){copy(arg); return *this;} virtual ~GAGenome(); virtual GAGenome* clone(CloneMethod flag=CONTENTS) const; virtual void copy(const GAGenome &); #ifdef GALIB_USE_STREAMS virtual int read(STD_ISTREAM &) { GAErr(GA_LOC, className(), "read", gaErrOpUndef); return 0; } virtual int write(STD_OSTREAM &) const { GAErr(GA_LOC, className(), "write", gaErrOpUndef); return 0; } #endif virtual int equal(const GAGenome &) const { GAErr(GA_LOC, className(), "equal", gaErrOpUndef); return 1; } virtual int notequal(const GAGenome & g) const { return (equal(g) ? 0 : 1); } public: int nevals() const {return _neval;} float score() const { evaluate(); return _score; } float score(float s){ _evaluated=gaTrue; return _score=s; } float fitness(){return _fitness;} float fitness(float f){return _fitness = f;} GAGeneticAlgorithm* geneticAlgorithm() const {return ga;} GAGeneticAlgorithm* geneticAlgorithm(GAGeneticAlgorithm& g){return(ga=&g);} void * userData() const {return ud;} void * userData(void * u){return(ud=u);} GAEvalData * evalData() const {return evd;} GAEvalData * evalData(const GAEvalData& o) {delete evd; evd = o.clone(); return evd;} float evaluate(GABoolean flag = gaFalse) const; Evaluator evaluator() const {return eval;} Evaluator evaluator(Evaluator f) { _evaluated=gaFalse; return(eval=f); } void initialize(){_evaluated=gaFalse; _neval=0; (*init)(*this);} Initializer initializer() const {return init;} Initializer initializer(Initializer op){return (init=op);} int mutate(float p){ return((*mutr)(*this,p)); } Mutator mutator() const {return mutr;} Mutator mutator(Mutator op){return (mutr=op);} float compare(const GAGenome& g) const {return (*cmp)(*this,g);} Comparator comparator() const {return cmp;} Comparator comparator(Comparator c){return (cmp=c);} SexualCrossover crossover(SexualCrossover f) { return sexcross = f; } SexualCrossover sexual() const { return sexcross; } AsexualCrossover crossover(AsexualCrossover f) { return asexcross = f; } AsexualCrossover asexual() const { return asexcross; } protected: float _score; // value returned by the objective function float _fitness; // (possibly scaled) fitness score GABoolean _evaluated; // has this genome been evaluated? unsigned int _neval; // how many evaluations since initialization? GAGeneticAlgorithm* ga; // the ga that is using this genome void* ud; // pointer to user data Evaluator eval; // objective function GAEvalData* evd; // evaluation data (specific to each genome) Mutator mutr; // the mutation operator to use for mutations Initializer init; // how to initialize this genome Comparator cmp; // how to compare two genomes of this type SexualCrossover sexcross; // preferred sexual mating method AsexualCrossover asexcross; // preferred asexual mating method }; #ifdef GALIB_USE_STREAMS inline STD_OSTREAM & operator<< (STD_OSTREAM& os, const GAGenome& genome) { genome.write(os); return(os); } inline STD_ISTREAM & operator>> (STD_ISTREAM & is, GAGenome& genome) { genome.read(is); return(is); } #endif inline int operator== (const GAGenome& a, const GAGenome& b) { return a.equal(b); } inline int operator!= (const GAGenome& a, const GAGenome& b) { return a.notequal(b); } #endif galib247/ga/gaid.h0100644003643600364360000000742610573535473013117 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- id.h mbwall 7may95 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved DESCRIPTION: This defines the identifiers for polymorphic classes. The IDs are used primarily for checking to be see if the two objects are the same type before doing a copy, for example. The name is often used when printing out error messages so you'll know where things are happening. I hate to derive so many classes from the same base class, especially when the derived classes are completely unrelated. But this is a convenient way to enumerate the built-in classes, and they DO share the polymorphic behaviour (even if they do NOT share any other attributes). TO DO: I leave the id/classname implementation for backward compatibility. Also, as of fall98 there are still some systems that do not support RTTI (or environs that do not want to use RTTI for some reason or another). This whole thing will be replaced with a proper RTTI implementation as soon as RTTI is stable on all the platforms (and as soon as I have time to do the update). So for now, I apologize for the 'hack'iness of this implementation. ---------------------------------------------------------------------------- */ #ifndef _ga_id_h_ #define _ga_id_h_ class GAID { public: enum { BaseGA=0, SimpleGA, SteadyStateGA, IncrementalGA, DemeGA, Population=10, Scaling=15, NoScaling, LinearScaling, SigmaTruncationScaling, PowerLawScaling, Sharing, Selection=40, RankSelection, RouletteWheelSelection, TournamentSelection, UniformSelection, SRSSelection, DSSelection, Genome=50, BinaryStringGenome, BinaryStringGenome2D, BinaryStringGenome3D, Bin2DecGenome, ListGenome, TreeGenome, ArrayGenome, ArrayGenome2D, ArrayGenome3D, ArrayAlleleGenome, ArrayAlleleGenome2D, ArrayAlleleGenome3D, StringGenome, FloatGenome, IntGenome, DoubleGenome }; int sameClass(const GAID &b) const {return(classID() == b.classID());} virtual const char * className() const {return "no class";} virtual int classID() const {return 0;} virtual ~GAID() { } }; // Here are the ID values for the GA library: // // class range // --------------------------------------------- // reserved 0-199 // anyone can use these 200- // // The ID numbers for built-in classes are enumerated in the GAID class. Sorry // but I had to do the dimension at the end of the names rather than at the // beginning since you cannot use a digit to start a variable name. // If you derive your own polymorphic class or specialize a // template class, then give it its own ID number and class name in the // specialization (see the string and real number specializations for examples) // Use these macros to define the identity for your class. If you do not use // these macros then your object will be identity-less. // Here's how to use the macro. // // class GASimpleGA : public GA { // public: // GADefineClassIdentity("GASimpleGA", 1); // ... // }; // // Notice that your template classes will all have the same name using this // method unless you specialize. For example, GA1DArrayGenome and // GA1DArrayGenome will both have the name GA1DArrayGenome as well as // the same number. Beware. #define GADefineIdentity(name,id) \ const char * className() const {return name;} \ int classID() const {return id;} #define GADeclareIdentity() \ const char * className() const; \ int classID() const #define GADefineIdentitySRC(clss,name,id) \ const char * clss :: className() const {return name;} \ int clss :: classID() const {return id;} #endif galib247/ga/GAIncGA.C0100644003643600364360000001476710573535473013305 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- gainc.C mbwall 28jul94 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved Source file for the incremental genetic algorithm object. ---------------------------------------------------------------------------- */ #include #include GAParameterList& GAIncrementalGA::registerDefaultParameters(GAParameterList& p) { GAGeneticAlgorithm::registerDefaultParameters(p); p.add(gaNnOffspring, gaSNnOffspring, GAParameter::INT, &gaDefNumOff); p.set(gaNscoreFrequency, &gaDefScoreFrequency2); return p; } GAIncrementalGA::GAIncrementalGA(const GAGenome& c) : GAGeneticAlgorithm(c) { child1 = pop->individual(0).clone(GAGenome::ATTRIBUTES); child2 = pop->individual(0).clone(GAGenome::ATTRIBUTES); child1->geneticAlgorithm(*this); child2->geneticAlgorithm(*this); rs = WORST; rf = 0; noffspr = gaDefNumOff; params.add(gaNnOffspring, gaSNnOffspring, GAParameter::INT, &noffspr); stats.scoreFrequency(gaDefScoreFrequency2); params.set(gaNscoreFrequency, &gaDefScoreFrequency2); } GAIncrementalGA::GAIncrementalGA(const GAPopulation& p): GAGeneticAlgorithm(p){ child1 = pop->individual(0).clone(GAGenome::ATTRIBUTES); child2 = pop->individual(0).clone(GAGenome::ATTRIBUTES); child1->geneticAlgorithm(*this); child2->geneticAlgorithm(*this); rs = WORST; rf = 0; noffspr = gaDefNumOff; params.add(gaNnOffspring, gaSNnOffspring, GAParameter::INT, &noffspr); stats.scoreFrequency(gaDefScoreFrequency2); params.set(gaNscoreFrequency, &gaDefScoreFrequency2); } GAIncrementalGA::GAIncrementalGA(const GAIncrementalGA& ga) : GAGeneticAlgorithm(ga){ child1 = (GAGenome *)0; child2 = (GAGenome *)0; copy(ga); } GAIncrementalGA::~GAIncrementalGA(){ delete child1; delete child2; } GAIncrementalGA& GAIncrementalGA::operator=(const GAIncrementalGA& ga){ if(&ga != this) copy(ga); return *this; } void GAIncrementalGA::copy(const GAGeneticAlgorithm & g){ GAGeneticAlgorithm::copy(g); const GAIncrementalGA& ga = DYN_CAST(const GAIncrementalGA&, g); rs = ga.rs; rf = ga.rf; noffspr = ga.noffspr; if(child1) child1->copy(*ga.child1); else child1 = ga.child1->clone(); if(child2) child2->copy(*ga.child2); else child2 = ga.child2->clone(); child1->geneticAlgorithm(*this); child2->geneticAlgorithm(*this); } int GAIncrementalGA::setptr(const char* name, const void* value){ int status = GAGeneticAlgorithm::setptr(name, value); if(strcmp(name, gaNnOffspring) == 0 || strcmp(name, gaSNnOffspring) == 0){ nOffspring(*((int*)value)); status = 0; } return status; } int GAIncrementalGA::get(const char* name, void* value) const { int status = GAGeneticAlgorithm::get(name, value); if(strcmp(name, gaNnOffspring) == 0 || strcmp(name, gaSNnOffspring) == 0){ *((int*)value) = noffspr; status = 0; } return status; } void GAIncrementalGA::objectiveFunction(GAGenome::Evaluator f){ GAGeneticAlgorithm::objectiveFunction(f); child1->evaluator(f); child2->evaluator(f); } void GAIncrementalGA::objectiveData(const GAEvalData& v){ GAGeneticAlgorithm::objectiveData(v); child1->evalData(v); child2->evalData(v); } GAIncrementalGA::ReplacementScheme GAIncrementalGA:: replacement(GAIncrementalGA::ReplacementScheme n, GAIncrementalGA::ReplacementFunction f){ switch(n){ case BEST: case WORST: case RANDOM: case PARENT: rs = n; break; case CUSTOM: if(f){ rs = n; rf = f; } else GAErr(GA_LOC, className(), "replacement", gaErrNeedRS); break; default: GAErr(GA_LOC, className(), "replacement", gaErrBadRS); break; } return rs; } int GAIncrementalGA::nOffspring(unsigned int value){ if(value != 1 && value != 2){ GAErr(GA_LOC, className(), "numCrossStrategy", gaErrBadCS); noffspr = 1; } else{ noffspr = value; } params.set(gaNnOffspring, value); return noffspr; } // Do some basic stupidity checks then initialize the population. We must // also initialize our temporary genomes, but we don't have to evaluate // them. Finally, reset the statistics. void GAIncrementalGA::initialize(unsigned int seed) { GARandomSeed(seed); pop->initialize(); pop->evaluate(gaTrue); stats.reset(*pop); if(!scross) GAErr(GA_LOC, className(), "initialize", gaErrNoSexualMating); } // Evolve a new generation of genomes. A steady-state GA has no 'old' // and 'new' populations - we pick from the current population and replace its // members with the new ones we create. We generate either one or two children // each 'generation'. The replacement strategy is set by the GA. void GAIncrementalGA::step() { int mut, c1, c2; GAGenome *mom, *dad; // tmp holders for selected genomes mom = &(pop->select()); dad = &(pop->select()); stats.numsel += 2; // keep track of the number of selections if(noffspr == 1){ c1 = 0; if(GAFlipCoin(pCrossover())){ stats.numcro += (*scross)(*mom, *dad, child1, (GAGenome*)0); c1 = 1; } else{ if(GARandomBit()) child1->copy(*mom); else child1->copy(*dad); } stats.nummut += (mut = child1->mutate(pMutation())); if(mut > 0) c1 = 1; stats.numeval += c1; if(rs == PARENT) child1 = pop->replace(child1, mom); else if(rs == CUSTOM) child1 = pop->replace(child1, &(rf(*child1, *pop))); else child1 = pop->replace(child1, rs); stats.numrep += 1; } else{ c1 = c2 = 0; if(GAFlipCoin(pCrossover())){ stats.numcro += (*scross)(*mom, *dad, child1, child2); c1 = c2 = 1; } else{ child1->copy(*mom); child2->copy(*dad); } stats.nummut += (mut = child1->mutate(pMutation())); if(mut > 0) c1 = 1; stats.nummut += (mut = child2->mutate(pMutation())); if(mut > 0) c2 = 1; stats.numeval += c1 + c2; if(rs == PARENT){ child1 = pop->replace(child1, mom); if(mom == dad) // this is a possibility, if so do worst child2 = pop->replace(child2, GAPopulation::WORST); else child2 = pop->replace(child2, dad); } else if(rs == CUSTOM){ child1 = pop->replace(child1, &(rf(*child1, *pop))); child2 = pop->replace(child2, &(rf(*child2, *pop))); } else{ child1 = pop->replace(child1, rs); child2 = pop->replace(child2, rs); } stats.numrep += 2; } pop->evaluate(gaTrue); // allow pop-based evaluators to do their thing stats.update(*pop); // update the statistics for this generation } galib247/ga/GAIncGA.h0100644003643600364360000000711010573535473013332 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- gainc.h mbwall 28jul94 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved Header file for the incremental genetic algorithm class. replacement The replacement strategy defines how the new children will be stuck into the population. If you want the new child to replace one of its parents, use the Parent strategy. If you want the child to replace a random population member, use the Random strategy. If you want the child to replace the worst population member, use the Worst strategy. These are meaningful only for overlapping populations. To do DeJong-style speciation (crowding), use the Crowding strategy. You must also specify a crowding function as the replacement function if you choose this strategy. If you use Custom as the replacement strategy you must also specify a replacement function. Note that not every replacement scheme can be used with every type of genetic algorithm. If a GA supports replacement schemes, it will specify which schemes are valid and which are not. The replacement function is required for crowding and custom replacement strategies. This function is used to pick which genome will be replaced. The first argument passed to the replacement function is the individual that is supposed to go into the population. The second argument is the population into which the individual is supposed to go. The replacement function should return a reference to the genome that the individual should replace. If no replacement should take place, the replacement function should return a reference to the individual. ---------------------------------------------------------------------------- */ #ifndef _ga_gainc_h_ #define _ga_gainc_h_ #include class GAIncrementalGA : public GAGeneticAlgorithm { public: GADefineIdentity("GAIncrementalGA", GAID::IncrementalGA); typedef GAGenome & (*ReplacementFunction)(GAGenome&, GAPopulation&); enum ReplacementScheme { RANDOM = GAPopulation::RANDOM, BEST = GAPopulation::BEST, WORST = GAPopulation::WORST, CUSTOM = -30, CROWDING = -30, PARENT = -10 }; static GAParameterList& registerDefaultParameters(GAParameterList&); public: GAIncrementalGA(const GAGenome&); GAIncrementalGA(const GAPopulation&); GAIncrementalGA(const GAIncrementalGA&); GAIncrementalGA& operator=(const GAIncrementalGA&); virtual ~GAIncrementalGA(); virtual void copy(const GAGeneticAlgorithm &); virtual void initialize(unsigned int seed=0); virtual void step(); GAIncrementalGA & operator++() { step(); return *this; } virtual int setptr(const char* name, const void* value); virtual int get(const char* name, void* value) const; virtual void objectiveFunction(GAGenome::Evaluator f); virtual void objectiveData(const GAEvalData& v); int nOffspring() const {return noffspr;} int nOffspring(unsigned int); ReplacementScheme replacement() const {return rs;} ReplacementScheme replacement(ReplacementScheme, ReplacementFunction f=0); protected: GAGenome *child1, *child2; // children that will be generated each gen ReplacementScheme rs; // replacement strategy ReplacementFunction rf; // (optional) replacement function unsigned int noffspr; // number of children to generate in crossover }; #ifdef GALIB_USE_STREAMS inline STD_OSTREAM & operator<< (STD_OSTREAM & os, GAIncrementalGA & arg) { arg.write(os); return(os); } inline STD_ISTREAM & operator>> (STD_ISTREAM & is, GAIncrementalGA & arg) { arg.read(is); return(is); } #endif #endif galib247/ga/GAList.C0100644003643600364360000001333610573535474013267 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- listtmpl.C mbwall 25feb95 Copyright 1995 Massachusetts Institute of Technology DESCRIPTION: This defines the templatized list objects. TO DO: Make insert work better with size and depth so not so many recalcs needed. Implement better memory mangement, faster allocation, referencing. Use array representation of nodes so we don't have to do so much recursion. ---------------------------------------------------------------------------- */ #ifndef _ga_listtmpl_C_ #define _ga_listtmpl_C_ #include extern GANodeBASE * _GAListTraverse(unsigned int index, unsigned int & cur, GANodeBASE * node); //template GANode * _GAListCopy(GANode *, GANode *); /* ---------------------------------------------------------------------------- List ---------------------------------------------------------------------------- */ // The destructor just goes through the list and deletes every node. template GAList::~GAList() { while(hd) delete GAListBASE::remove(DYN_CAST(GANode*, hd)); iter.node = (GANodeBASE *)0; } // Yes, this is really ugly. We do a complete destruction of the existing list // then we copy the new one. No caching, no nothing. Oh well. We set the // iterator to the head node - it should be set to the corresponding node, but // I won't do that right now. THIS IS A BUG! template void GAList::copy(const GAList & orig) { while(hd) delete GAListBASE::remove(DYN_CAST(GANode*, hd)); hd = _GAListCopy(DYN_CAST(GANode*, orig.hd), DYN_CAST(GANode*, orig.hd)); iter.node = hd; sz = orig.sz; csz = orig.csz; } // This remove method returns a pointer to the contents of the node that was // removed. The node itself is destroyed. // The iterator gets set to the next node toward the head of the list. // This routine makes a copy of the node contents using the copy initializer // of the T object, so the copy initializer MUST be defined and accessible. // We return a pointer to the contents rather than the contenst for the same // reason we return a pointer from all the iter routines - we don't want to // pass big objects around. template T * GAList::remove() { GANode * node = DYN_CAST(GANode*, iter.node); if(!node) return (T *)0; if(node->prev != node) iter.node = node->prev; else iter.node = (GANodeBASE *)0; node = DYN_CAST(GANode*, GAListBASE::remove(node)); T * contents = new T(node->contents); delete node; return contents; } // Make a copy of a list and return the pointer to the new list. The cloning // is based on the value passed to this routine. A value of 0 will clone the // entire list. Any other value will clone the list from the index to the end // of the list. This routine has no effect on the iterator in the original // list. template GAList * GAList::clone(unsigned int i) const { GAList * t = new GAList; GANode * node; unsigned int w=0; if(i == 0) node = DYN_CAST(GANode*, hd); else node = DYN_CAST(GANode*, _GAListTraverse(i, w, hd)); if(!node) return t; GANode * newnode = _GAListCopy(node, DYN_CAST(GANode*, hd)); t->insert(newnode, (GANode *)0, GAListBASE::HEAD); // need to set iterator to right spot in the clone!! for now its at the head return t; } // Destroy the specified node. This uses the current node as the one to // destroy, so be sure to use the iteration methods to move to the node you // want to destroy. Once the node is gone, we set the current node to the // prev node of the one that was destroyed. If the node that was nuked was the // head node then we set the current node to the new head. template int GAList::destroy() { GANodeBASE * node = iter.node; if(!node) return GAListBASE::NO_ERR; if(node->prev && node->prev != node) if(hd == node) iter.node = node->next; else iter.node = node->prev; else iter.node = (GANodeBASE *)0; delete GAListBASE::remove(node); return GAListBASE::NO_ERR; } // Swap two nodes in the list. This has no effect on the size or the iterator. // If either index is out of bounds then we don't do anything. template int GAList::swap(unsigned int a, unsigned int b) { if(a == b || a > (unsigned int)size() || b > (unsigned int)size()) return GAListBASE::NO_ERR; GANodeBASE *tmp=hd, *anode=(GANodeBASE *)0, *bnode=(GANodeBASE *)0; unsigned int cur=0; while(tmp && tmp->next != hd){ if(a == cur) anode = tmp; if(b == cur) bnode = tmp; tmp = tmp->next; cur++; } if(a == cur) anode = tmp; if(b == cur) bnode = tmp; return GAListBASE::swapnode(anode,bnode); } /* ---------------------------------------------------------------------------- Utility routines for the List objects ---------------------------------------------------------------------------- */ // Copy a node, including all of its siblings up to the end of the list. We do // NOT wrap around the list until we return the first node - we stop at the // tail of the list. Return the pointer to the first node in the list. template GANode * _GAListCopy(GANode * node, GANode * head) { if(!node) return (GANode *)0; GANode *newnode = new GANode(node->contents); GANode *lasttmp = newnode, *newtmp = (GANode *)0; GANode *tmp = DYN_CAST(GANode*, node->next); while(tmp && tmp != head){ newtmp = new GANode(tmp->contents); newtmp->prev = lasttmp; lasttmp->next = newtmp; lasttmp = newtmp; tmp = DYN_CAST(GANode*, tmp->next); } if(newtmp){ newtmp->next = newnode; newnode->prev = newtmp; } else{ newnode->next = newnode; newnode->prev = newnode; } return newnode; } #endif galib247/ga/GAList.h0100644003643600364360000001740010573535474013330 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- listtmpl.h mbwall 25feb95 Copyright 1995 Massachusetts Institute of Technology DESCRIPTION: This defines the template-ized list objects. ---------------------------------------------------------------------------- */ #ifndef _ga_listtmpl_h_ #define _ga_listtmpl_h_ #include #include /* ---------------------------------------------------------------------------- GAList ------------------------------------------------------------------------------- This object is a container for nodes that have a list structure. The base list object is responsible for maintaining the list heirarchy. This object is responsible for doing the memory management (allocating and de-allocating the nodes in the list). We insulate the user entirely from nodes - when you use a list, you don't get nodes back, you get the contents of nodes (ie the user doesn't have to think about the list parts of a node, they can simply assume that their data is organized into a list structure). We include an iterator in this object so that you can navigate through the list. You can create another iterator and assign it to your list so you can have multiple iterators. All of the actions take place relative to the current location of the embedded iterator. None of the iterators change the state of the list. Be careful so that you don't end up with an iterator dangling with a pointer to a part of a list that no longer exists (I would need some kind of reference counting and/or message passing to take care of this at a lower level, and I'm not ready to implement that at this point). For now we allocate nodes on the fly. Eventually I would like to do some better memory management (arrays perhaps?) so we don't have to do so much alloc and dealloc and recursion. We depend on the template-ized GAListIter routine, thus the declaration. copy Make a complete copy of the list and return a pointer to the new list. remove Remove the current node from the list, free the memory used by the node, and return a pointer to a copy of the object that the node contained. destroy Remove the current node from the list and free the memory it was using. Destroys the object that the node contained. insert - list Inserts the contents of list in to the current list and removes it from the original list. Does NOT delete the original list, but DOES assume responsibility for the memory used by the contents of the original list. insert - object Insert the object into the list at the specified place relative to the current location of the embedded iterator. current, head, tail, next, prev, warp These iterator methods are defined as access to the embedded iterator of the list. Use these methods to move the insertion point and to traverse the list. You can also create other iterators for this list, but they won't affect the contents. ---------------------------------------------------------------------------- */ template class GAListIter; template class GAList : public GAListBASE { public: GAList() : GAListBASE() { iter(*this); } GAList(const T & t):GAListBASE(new GANode(t)), iter(*this) {} GAList(const GAList & orig){iter(*this); copy(orig);} GAList & operator=(const GAList & orig) {if(&orig != this) copy(orig); return *this;} virtual ~GAList(); GAList * clone(unsigned int i=0) const; // methods that modify the state of the list void copy(const GAList & orig); int destroy(); int swap(unsigned int, unsigned int); T * remove(); int insert(GAList * t, GAListBASE::Location where=GAListBASE::AFTER){ if(this == t){ GAErr(GA_LOC, "GAList", "insert", gaErrCannotInsertIntoSelf); return GAListBASE::ERR; } if(GAListBASE::insert(t->hd, iter.node, where) == GAListBASE::ERR){ return GAListBASE::ERR; } iter.node = (t->hd ? t->hd : iter.node); t->hd=(GANodeBASE *)0; t->iter.node=(GANodeBASE *)0; return GAListBASE::NO_ERR; } int insert(const T & t, GAListBASE::Location where=GAListBASE::AFTER){ GANode * c = new GANode(t); if(GAListBASE::insert(c, iter.node, where) == GAListBASE::ERR){ delete c; return GAListBASE::ERR; } iter.node = c; return GAListBASE::NO_ERR; } // typesafes on iteration methods. These call the built-in iterator then // return the contents of the now-current node. They do not affect the state // of the list. T * head(){return iter.head();} T * tail(){return iter.tail();} T * current(){return iter.current();} T * next(){return iter.next();} T * prev(){return iter.prev();} T * warp(unsigned int i){return iter.warp(i);} T * warp(const GAListIter & i) {return((i.list == this) ? iter.warp(i) : (T *)0);} T * operator[](unsigned int i){return iter.warp(i);} protected: int insert(GANode *n, GANode *idx, GAListBASE::Location where=GAListBASE::AFTER){ if(GAListBASE::insert(n, idx, where) == GAListBASE::ERR) return GAListBASE::ERR; iter.node = n; return GAListBASE::NO_ERR; } GAListIter iter; // the embedded iterator friend class GAListIter; }; /* ---------------------------------------------------------------------------- GAListIter ------------------------------------------------------------------------------- This is a type-safe derivation of the base ListIter object. I copied the methods from the base class (I know, a no-no) rather than doing calls to the base class methods. We depend on the template-ized GAList, thus the declaration. Behaviour for the iterator methods is defined as follows. If the current node is null, attempts to access a derived position from the current position will return NULL. The only way to reset the current node is to call the head() locater (you always have to start at the list head to navigate the list). If the current node is non-null and the derived node is null, the current node is NOT changed, but NULL is returned. You can also warp to a new position if you have another iterator or a list with an embedded iterator. When we create a new list iterator, it defaults to the same node as the one used to create it. If it is created with a list as its argument, it defaults to the list's iterator's current position. ---------------------------------------------------------------------------- */ template class GAList; template class GAListIter : public GAListIterBASE { public: GAListIter() : GAListIterBASE(){} GAListIter(const GAList & t) : GAListIterBASE(t){node=t.iter.node;} GAListIter(const GAListIter & i) : GAListIterBASE(i){} T * current() {return(node ? &((GANode *)node)->contents : (T *)0);} T * head() {return(((node=GAListIterBASE::head()) != (GANodeBASE *)0) ? &((GANode *)GAListIterBASE::head())->contents : (T *)0);} T * tail() {return(((node=GAListIterBASE::tail()) != (GANodeBASE *)0) ? &((GANode *)GAListIterBASE::tail())->contents : (T *)0);} T * next() {return((node && node->next) ? &((GANode *)(node=node->next))->contents : (T *)0);} T * prev() {return((node && node->prev) ? &((GANode *)(node=node->prev))->contents : (T *)0);} T * warp(const GAList & t){ list = &t; node = t.iter.node; return(t.iter.node ? &((GANode *)(node=t.iter.node))->contents :(T *)0); } T * warp(const GAListIter & i){ list = i.list; node = i.node; return(i.node ? &((GANode *)(node=i.node))->contents : (T *)0); } T * warp(unsigned int i){ GANodeBASE * n = GAListIterBASE::warp(i); return(n ? &((GANode *)(node=n))->contents : (T *)0); } private: friend class GAList; // do I need to do this? }; #ifdef GALIB_USE_BORLAND_INST #include #endif #endif galib247/ga/GAListBASE.C0100644003643600364360000002011010573535473013705 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- listbase.C mbwall 10dec94 Copyright 1995 Massachusetts Institute of Technology DESCRIPTION: This defines the list objects. TO DO: Make insert work better with size and depth so not so many recalcs needed. Implement better memory mangement, faster allocation, referencing. Use array representation of nodes so we don't have to do so much recursion. ---------------------------------------------------------------------------- */ #include #include GANodeBASE * _GAListTraverse(unsigned int index, unsigned int & cur, GANodeBASE * node); /* ---------------------------------------------------------------------------- ListBASE ---------------------------------------------------------------------------- */ // Insert node n into the list relative to node idx. There are three different // insertion modes: head, before, and after. If there is no head node, // then the node n becomes the head no matter what. // We have to check to see if the node that is going in is an isolated node // or contains other nodes. If it is linked to other nodes, then we put the // entire set of nodes into the list. If the nodes' prev and next are NULL or // point to itself, then we stick only it into the list. // head: idx is ignored. The previous head pointer becomes 'next' to the // new head. // before: If node idx is the first in a row in the list, then n becomes // the first in the row. If idx is the head node, then we post an error // message (can't have more than one head node). // after: If the node idx is the last in a row, n becomes the last node. If // idx is the head node, we post an error. int GAListBASE::insert(GANodeBASE * n, GANodeBASE * idx, Location where) { if(!n) return NO_ERR; if(!idx){ if(!hd) where = HEAD; else if(where != HEAD && where != TAIL){ GAErr(GA_LOC, "GAListBASE", "insert", gaErrCannotInsertOnNilNode); return ERR; } } GANodeBASE * last = (n->prev && n->prev != n) ? n->prev : n; switch(where){ case HEAD: if(hd){ last->next = hd; n->prev = hd->prev; hd->prev->next = n; hd->prev = last; } hd = n; if(!hd->next) hd->next = hd; if(!hd->prev) hd->prev = hd; break; case TAIL: if(hd){ last->next = hd; n->prev = hd->prev; hd->prev->next = n; hd->prev = last; } else{ hd = n; if(!hd->next) hd->next = hd; if(!hd->prev) hd->prev = hd; } break; case BEFORE: last->next = idx; n->prev = idx->prev; idx->prev->next = n; idx->prev = last; break; case AFTER: n->prev = idx; last->next = idx->next; idx->next->prev = last; idx->next = n; break; default: GAErr(GA_LOC, "GAListBASE", "insert", gaErrBadWhereIndicator); break; } csz = 1; return NO_ERR; } // Remove the specified node from the list. We don't cruise through the list // to make certain that the node is in the list. But we do check to make sure // that the connections were ok before we prune the node. If there is any // problem with the links, we return a NULL. If we get a NULL node, then we // don't do anything. // We don't do anything to the next, prev, etc links of the node that is // being removed (they are left pointing to where they used to point) so be // careful!! // If the removal is on the head node, set the head node to the next node. GANodeBASE * GAListBASE::remove(GANodeBASE * n) { if(!n) return (GANodeBASE *)0; if(n->next && n->next != n){ // reset links on neighbors if they exist n->prev->next = n->next; n->next->prev = n->prev; } if(n == hd){ // reset head node if needed if(n->next != n) hd = n->next; else hd = (GANodeBASE *)0; } // uncomment these to modify the node that is getting removed // n->prev = n; // n->next = n; csz = 1; return n; } // Swap the specified nodes. If we get NULL nodes or the nodes are the same, // don't do anything. This moves the two nodes. Note // that swapping two nodes shouldn't change the size or depth of the list, so // we don't set the change flags. // If either of the nodes is the head of the list, we change the head to // point to the node that got swapped. Note that if you pass nodes that are // in different trees and one of the nodes is a head node, you'll lose an // entire list! // There is a special case we must handle when the nodes are adjacent. We // assume that the nodes are intact - we don't check for bogus node // configurations. We assume that there are no NULL prev or next pointers on // either node. // For now we assume that both nodes are in the same list. If we ever // implement a swap that operates on two lists then we'll have to change // that... int GAListBASE::swapnode(GANodeBASE * a, GANodeBASE * b) { if(!a || !b || a == b) return NO_ERR; GANodeBASE * aprev = a->prev; GANodeBASE * anext = a->next; GANodeBASE * bprev = b->prev; GANodeBASE * bnext = b->next; if(anext == b && bnext == a){ // do nothing - check for head/tail at end } else if(anext == b){ // same as b->prev == a a->prev = b; a->next = bnext; b->prev = aprev; b->next = a; aprev->next = b; bnext->prev = a; } else if(bnext == a){ // same as a->prev == b a->prev = bprev; a->next = b; b->prev = a; b->next = anext; anext->prev = b; bprev->next = a; } else{ // a and b are not adjacent if(bprev == b || bnext == b){ a->prev = a; a->next = a; } else{ a->prev = bprev; a->next = bnext; bprev->next = a; bnext->prev = a; } if(aprev == a || anext == a){ b->prev = b; b->next = b; } else{ b->prev = aprev; b->next = anext; aprev->next = b; anext->prev = b; } } if(hd == a) hd = b; // this only works if they're in the same list! else if(hd == b) hd = a; return NO_ERR; } // Return the number of nodes in the list. We do a complete traversal of the // list and count the number of nodes that we encounter. Could do this breadth // first or depth first - doesn't really matter. We have to traverse the // entire list to do the count. // We have to do a little work-around here to get through the const-ness of // the size method. Its ok to call size on a const object because it does not // modify the logical state of the object. It does, however, modify the // physical state of the object. So to work around the strictness of the // const specifier, we do a little pointer magic and cast this to be non-const. int GAListBASE::size() const { if(!csz) return sz; GAListBASE * This = CON_CAST(GAListBASE *, this); This->csz = 0; if(hd == (GANodeBASE *)0) return This->sz=0; GANodeBASE * tmp = hd; This->sz=1; while(tmp && tmp->next != hd){ tmp = tmp->next; This->sz++; } return This->sz; } /* ---------------------------------------------------------------------------- ListIterBASE ---------------------------------------------------------------------------- */ // Set the current node to the node indexed by the integer x. If x is out of // bounds, we don't do anything to the state of the iterator and return NULL. GANodeBASE * GAListIterBASE::warp(unsigned int x) { unsigned int cur=0; return(_GAListTraverse(x, cur, GAListIterBASE::head())); } /* ---------------------------------------------------------------------------- utilities ---------------------------------------------------------------------------- */ // Traverse the list until we come to the indexed node. Return NULL if // cur != index. We count relative to the node that is passed to this routine // so to get an absolute count, pass 0 for 'cur' and the root node for 'node'. // If the index is out of bounds, we return NULL. GANodeBASE * _GAListTraverse(unsigned int index, unsigned int & cur, GANodeBASE * node) { if(!node) return (GANodeBASE *)0; GANodeBASE * tmp = node; while(cur < index && tmp && tmp->next != node){ tmp = tmp->next; cur++; } if(cur != index) tmp = 0; // we didn't find the right node return tmp; } galib247/ga/GAListBASE.h0100644003643600364360000001606410573535473013767 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- listbase.h mbwall 25nov94 Copyright 1995 Massachusetts Institute of Technology DESCRIPTION: This defines the list objects. TO DO: Probably should put the size (and depth for trees) into the templateized class since those take care of memory management. BASE class has no concept of memory management, nor does it know the best way to count what its got. ---------------------------------------------------------------------------- */ #ifndef _ga_listbase_h_ #define _ga_listbase_h_ #include /* ---------------------------------------------------------------------------- GAListBASE ------------------------------------------------------------------------------- This is the base list class from which template lists are derived. This object does no memory management - it just keeps track of a list structure. Whoever calls the members of this object is responsible for allocating and deallocating the memory associated with each node. This class does not define any of the iteration operators for traversing the list. That is left to the iterator friend of this class. The iterator class is declared as a friend so that it can access our internals. It iterates over the list without changing anything. We have to break through the const-ness of the list in order to make things work properly. When you ask for the size of a list, you don't change the size but you do (possibly) change the value of the sz member. This doesn't change the state of the tree, so it is, in effect, a const-correct operation. But const is too strict, so we have to work around it. See the size() definition to see how this is done. Beware that copying this object will copy pointers, NOT the contents of the pointers. You cannot simply say list1 = list2 or GAListBASE l = list1. If you do this, you'll get a copy of the list object, but not a duplicate of the list. creation You can create a list by passing a node (the node becomes the head of the list) or by passing nothing (the head of the list is NULL, and the next insert automatically becomes the head). insert Stick a node into the list. Where the node goes depends on the second node and the value of the flag. There are three flag values: head, before, and after. The flag specifies where the new node should go relative to the old node. If you don't pass a value for flag, it defaults to after. The syntax for using the insert method looks like this: mylist.insert(newnode, oldnode, GAListBASE::before); mylist.insert(newnode, oldnode); The node can be a member of a list. If it is, then the list will be broken just previous to the node, then inserted into the list. If the insert was successful, return NO_ERR. If there was a problem, return ERR. remove Remove the specified node from the list. If the node does not exist, an ERR message is posted and NULL is returned. The node is returned if the removal is successful, otherwise NULL. swapnode Switch nodes a and b in the list. Leave the rest of the list intact. If the swap was successful, return NO_ERR. If there was a problem, return ERR. size How many nodes are in the list? We keep a flag to tell us if any operation has been performed that would require a recalculation of the size. If you change the contents of the list using any method other than those in this object (which you could do, by the way) then you risk screwing up the count. ---------------------------------------------------------------------------- */ class GAListBASE { public: enum Location {HEAD=0, TAIL, BEFORE, AFTER}; // values for 'where' to insert enum {NO_ERR=0, ERR= -1}; // return codes GAListBASE(){hd=(GANodeBASE *)0; sz=0; csz=0;} GAListBASE(GANodeBASE * n){hd=n; csz=1;} GANodeBASE * remove(GANodeBASE * n); int insert(GANodeBASE * n, GANodeBASE * idx, Location where=AFTER); int swapnode(GANodeBASE * a, GANodeBASE * b); int size() const; protected: int sz, csz; // number of nodes, have contents changed? GANodeBASE *hd; // the head node of the list private: GAListBASE(const GAListBASE &){} // copying is not allowed GAListBASE & operator=(const GAListBASE &){return *this;} // or op= friend class GAListIterBASE; }; /* ---------------------------------------------------------------------------- GAListIterBASE ------------------------------------------------------------------------------- This is the base class for iterators for the list objects. We define this class separately from the List object so that you can have multiple interators for each list and so that you can more easily customize the traversal algorithms within the iterator. From the object point of view, the way you traverse a list is independent of how you represent the list. Like the ListBASE object, this object doesn't do any memory allocation or deallocation. All we do is provide list traversal. Notice that we keep a 'current location' in the list - whatever your last query was is stored as the node, so if you refer to the current member, you'll get your last query. If you pass a NULL node to these routines they will not break; passing a NULL will result in a no-op, and NULL will be returned. creation When you create an iterator, you should pass another iterator (the new one will copy the first) or a list (the iterator will default to the head node of the list). current, head, tail, next, prev, warp Set the iterator to the specified node and return a pointer to the node that the iterator now points to. If current is NULL or a NULL is passed to one of these routines, a NULL is returned and the iterator does not move. warp Move the iterator to the node referenced by index. The head node is node '0' then the count increases from there. ---------------------------------------------------------------------------- */ class GAListIterBASE { public: GAListIterBASE(){node=(GANodeBASE *)0; list=(GAListBASE *)0;} GAListIterBASE(const GAListBASE & t){list = &t; node = t.hd;} GAListIterBASE(const GAListIterBASE & i){list = i.list; node = i.node;} void operator()(const GAListBASE & t){list = &t; node = t.hd;} GANodeBASE * current(GANodeBASE * c) {return(c ? (node=c) : (GANodeBASE *)0);} GANodeBASE * current(){return node;} GANodeBASE * next(){return(node ? (node=node->next) : (GANodeBASE *)0);} GANodeBASE * next(GANodeBASE * c) {return(c ? (node=c->next) : (GANodeBASE *)0);} GANodeBASE * prev(){return(node ? (node=node->prev) : (GANodeBASE *)0);} GANodeBASE * prev(GANodeBASE * c) {return(c ? (node=c->prev) : (GANodeBASE *)0);} GANodeBASE * head(){return(list ? (node=list->hd) : (GANodeBASE *)0);} GANodeBASE * tail() {return((list && list->hd)?(node=list->hd->prev) : (GANodeBASE *)0);} GANodeBASE * warp(unsigned int); GANodeBASE * warp(const GAListIterBASE & i){ list=i.list; node=(GANodeBASE *)0; return(i.node ? (node=i.node) : (GANodeBASE *)0); } int size(){return(list ? list->size() : 0);} protected: GANodeBASE * node; const GAListBASE * list; }; #endif galib247/ga/GAListGenome.C0100644003643600364360000004321210573535474014416 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- list.C mbwall 25feb95 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved DESCRIPTION: Source file for the list genome. ---------------------------------------------------------------------------- */ #ifndef _ga_list_C_ #define _ga_list_C_ #include #include #include #include #include template int GAListIsHole(const GAListGenome&, const GAListGenome&, int, int, int); template const char * GAListGenome::className() const {return "GAListGenome";} template int GAListGenome::classID() const {return GAID::ListGenome;} template GAListGenome::GAListGenome(GAGenome::Evaluator f, void * u) : GAList(), GAGenome(DEFAULT_LIST_INITIALIZER, DEFAULT_LIST_MUTATOR, DEFAULT_LIST_COMPARATOR) { evaluator(f); userData(u); crossover(DEFAULT_LIST_CROSSOVER); } template GAListGenome::GAListGenome(const GAListGenome & orig) : GAList(), GAGenome() { GAListGenome::copy(orig); } template GAListGenome::~GAListGenome() { } template GAGenome * GAListGenome::clone(GAGenome::CloneMethod flag) const { GAListGenome *cpy = new GAListGenome(); if(flag == (int)CONTENTS){cpy->copy(*this);} // the cast is for metrowerks... else{cpy->GAGenome::copy(*this);} return cpy; } template void GAListGenome::copy(const GAGenome & orig){ if(&orig == this) return; const GAListGenome* c = DYN_CAST(const GAListGenome*, &orig); if(c) { GAGenome::copy(*c); GAList::copy(*c); } } #ifdef GALIB_USE_STREAMS // Traverse the list (breadth-first) and dump the contents as best we can to // the stream. We don't try to write the contents of the nodes - we simply // write a . for each node in the list. template int GAListGenome::write(STD_OSTREAM & os) const { os << "node next prev contents\n"; if(!this->hd) return 0;; os.width(10); os << this->hd << " "; os.width(10); os << this->hd->next << " "; os.width(10); os << this->hd->prev << " "; os.width(10); os << &(DYN_CAST(GANode*, this->hd)->contents) << "\n"; for(GANodeBASE * tmp=this->hd->next; tmp && tmp != this->hd; tmp=tmp->next){ os.width(10); os << tmp << " "; os.width(10); os << tmp->next << " "; os.width(10); os << tmp->prev << " "; os.width(10); os << &(DYN_CAST(GANode*, tmp)->contents) << "\n"; } return 0; } #endif // Both the == and != operators assume that both operator== and operator!= are // defined for the object that is store in the node of your list. If it is // not, you'll get an error message. If you're storing pointers in the nodes, // then you have nothing to worry about. // Neither of these operators affects the internal iterator of either // list genome in any way. template int GAListGenome::equal(const GAGenome & c) const { if(this == &c) return 1; const GAListGenome & b = DYN_CAST(const GAListGenome&, c); if(this->size() != b.size()) return 0; GAListIter iterA(*this), iterB(b); T *tmpA = iterA.head(), *tmpB = iterB.head(); T *head = tmpA; do{ if(tmpA && tmpB && *tmpA != *tmpB) return gaFalse; tmpB = iterB.next(); tmpA = iterA.next(); }while(tmpA && tmpA != head); return 1; } /* ---------------------------------------------------------------------------- Operator definitions ---------------------------------------------------------------------------- */ // Mutate a list by nuking nodes. Any node has a pmut chance of getting nuked. // This is actually kind of bogus for the second part of the if clause (if nMut // is greater than or equal to 1). Nodes end up having more than pmut // probability of getting nuked. // After the mutation the iterator is left at the head of the list. template int GAListGenome::DestructiveMutator(GAGenome & c, float pmut) { GAListGenome &child=DYN_CAST(GAListGenome &, c); register int n, i; if(pmut <= 0.0) return 0; n = child.size(); float nMut = pmut * STA_CAST(float, n); if(nMut < 1.0){ // we have to do a flip test for each node nMut = 0; for(i=0; i int GAListGenome::SwapMutator(GAGenome & c, float pmut) { GAListGenome &child=DYN_CAST(GAListGenome &, c); register int n, i; if(pmut <= 0.0) return 0; n = child.size(); float nMut = pmut * STA_CAST(float,n); nMut *= 0.5; // swapping one node swaps another as well if(nMut < 1.0){ // we have to do a flip test for each node nMut = 0; for(i=0; i float GAListGenome::NodeComparator(const GAGenome& a, const GAGenome& b) { if(&a == &b) return 0; const GAListGenome& sis=DYN_CAST(const GAListGenome&, a); const GAListGenome& bro=DYN_CAST(const GAListGenome&, b); if(sis.size() > bro.size()) return (float)(sis.size() - bro.size()); if(sis.size() < bro.size()) return (float)(bro.size() - sis.size()); if(sis.size() == 0) return 0; float count = 0; GAListIter biter(bro), siter(sis); T *sptr, *bptr; for(int i=siter.size()-1; i>=0; i--) { sptr = siter.next(); bptr = biter.next(); if(sptr != 0 && bptr != 0) count += ((*sptr == *bptr) ? 0 : 1); } return count; } #define SWAP(a,b) {unsigned int tmp=a; a=b; b=tmp;} // This crossover picks a site between nodes in each parent. It is the same // as single point crossover on a resizeable binary string genome. The site // in the mother is not necessarily the same as the site in the father! // When we pick a crossover site, it is between nodes of the list (otherwise // we won't be able to do NULL lists or get an empty list from one parent or // the other). Beware that a list is numbered from 0 to size-1, inclusive, // whereas the cross site possibilities are numbered from 0 to size, inclusive. // This means we have to map the site to the list to determine whether an // insertion should occur before or after a node. // We first copy the mother into the child (this deletes whatever contents // were in the child originally). Then we clone the father from the cross site // to the end of the list. Then we delete the tail of the child from the // mother's cross site to the end of the list. Finally, we insert the clone // at the end of the child. // The last thing we do is delete the clone (the contents of the clone are // now owned by the child, but the clone itself uses memory that we must free). // This implementation isn't particularly efficient. For example, we copy // the mother then proceed to destroy much of the copy we just made. We could // do better by copying only what we need of the mother. template int GAListGenome:: OnePointCrossover(const GAGenome& p1, const GAGenome& p2, GAGenome* c1, GAGenome* c2){ const GAListGenome &mom=DYN_CAST(const GAListGenome &, p1); const GAListGenome &dad=DYN_CAST(const GAListGenome &, p2); int nc=0; int a = GARandomInt(0, mom.size()); int b = GARandomInt(0, dad.size()); GAList * list; if(c1){ GAListGenome &sis=DYN_CAST(GAListGenome &, *c1); sis.GAList::copy(mom); list = dad.GAList::clone(b); if(a < mom.size()){ T *site = sis.warp(a); while(sis.tail() != site) sis.destroy(); // delete the tail node sis.destroy(); // trash the trailing node (list[a]) } else{ sis.tail(); // move to the end of the list } sis.insert(list); // stick the clone onto the end delete list; sis.head(); // set iterator to head of list nc += 1; } if(c2){ GAListGenome &bro=DYN_CAST(GAListGenome &, *c2); bro.GAList::copy(dad); list = mom.GAList::clone(a); if(b < dad.size()){ T *site = bro.warp(b); while(bro.tail() != site) bro.destroy(); // delete the tail node bro.destroy(); // trash the trailing node (list[a]) } else{ bro.tail(); // move to the end of the list } bro.insert(list); // stick the clone onto the end delete list; bro.head(); // set iterator to head of list nc += 1; } return nc; } // Partial match crossover for list genomes. We need two versions of this // routine: one for lists whose nodes are pointers to objects (each genome // points to the same objects as all of the other genomes) and one for // lists whose nodes contain independent objects (each node has its own copy // of the object). // This version of the partial match crossover uses objects that are multiply // instantiated - each list genome contains its own objects in its nodes. // The operator== method must be defined on the object for this implementation // to work! In this case, the 'object' is an int, so we're OK. If you are // putting your own objects in the nodes, be sure you have operator== defined // for your object. You must also have operator!= defined for your object. We // do not do any assignments, so operator= and/or copy is not required. // We assume that none of the nodes will return a NULL pointer. Also assume // that the cross site has been selected properly. // First we make a copy of the mother. Then we loop through the match // section and try to swap each element in the child's match section with its // partner (as defined by the current node in the father's match section). // Mirroring will work the same way - just swap mom & dad and you're all set. // The parents should be the same size as the child (and they should contain // the same nodes, but in any order). We do not check for this!! template int GAListGenome:: PartialMatchCrossover(const GAGenome& p1, const GAGenome& p2, GAGenome* c1, GAGenome* c2){ const GAListGenome &mom=DYN_CAST(const GAListGenome &, p1); const GAListGenome &dad=DYN_CAST(const GAListGenome &, p2); if(mom.size() != dad.size()){ GAErr(GA_LOC, mom.className(), "cross", gaErrBadParentLength); return 0; } int a = GARandomInt(0, mom.size()); int b = GARandomInt(0, dad.size()); if(b &sis=DYN_CAST(GAListGenome &, *c1); sis.GAList::copy(mom); GAListIter diter(dad); index = diter.warp(a); for(i=a; isize } } sis.head(); // set iterator to head of list nc += 1; } if(c2){ GAListGenome &bro=DYN_CAST(GAListGenome &, *c2); bro.GAList::copy(dad); GAListIter miter(mom); index = miter.warp(a); for(i=a; isize } } bro.head(); // set iterator to head of list nc += 2; } return nc; } // Order crossover for lists. As described in Goldberg's book. // We assume that we'll never get a NULL pointer while iterating through the // list. Also we assume that the lists are the same size and non-NULL. template int GAListIsHole(const GAListGenome &child, const GAListGenome &parent, int index, int a, int b){ GAListIter citer(child), piter(parent); citer.warp(index); piter.warp(a); for(int i=a; i int GAListGenome:: OrderCrossover(const GAGenome& p1, const GAGenome& p2, GAGenome* c1, GAGenome* c2){ const GAListGenome &mom=DYN_CAST(const GAListGenome &, p1); const GAListGenome &dad=DYN_CAST(const GAListGenome &, p2); if(mom.size() != dad.size()){ GAErr(GA_LOC, mom.className(), "cross", gaErrBadParentLength); return 0; } int a = GARandomInt(0, mom.size()); int b = GARandomInt(0, dad.size()); if(b &sis=DYN_CAST(GAListGenome &, *c1); sis.GAList::copy(mom); GAListIter siter(sis); GAListIter diter(dad); // Move all the 'holes' into the crossover section and maintain the ordering of // the non-hole elements. for(i=0, index=b; i= sis.size()) index=0; if(GAListIsHole(sis,dad,index,a,b)) break; } for(; i= sis.size()) index=0; j=index; do{ j++; if(j >= sis.size()) j=0; } while(GAListIsHole(sis,dad,j,a,b)); sis.swap(index,j); } // Now put the 'holes' in the proper order within the crossover section. for(i=a, sis.warp(a), diter.warp(a); i &bro=DYN_CAST(GAListGenome &, *c2); bro.GAList::copy(dad); GAListIter biter(bro); GAListIter miter(mom); // Move all the 'holes' into the crossover section and maintain the ordering of // the non-hole elements. for(i=0, index=b; i= bro.size()) index=0; if(GAListIsHole(bro,mom,index,a,b)) break; } for(; i= bro.size()) index=0; j=index; do{ j++; if(j >= bro.size()) j=0; } while(GAListIsHole(bro,mom,j,a,b)); bro.swap(index,j); } // Now put the 'holes' in the proper order within the crossover section. for(i=a, bro.warp(a), miter.warp(a); i int GAListGenome:: CycleCrossover(const GAGenome& p1, const GAGenome& p2, GAGenome* c1, GAGenome* c2){ const GAListGenome &mom=DYN_CAST(const GAListGenome &, p1); const GAListGenome &dad=DYN_CAST(const GAListGenome &, p2); if(mom.size() != dad.size()){ GAErr(GA_LOC, mom.className(), "cross", gaErrBadParentLength); return 0; } GAMask mask; mask.size(mom.size()); mask.clear(); int i, nc=0; if(c1){ GAListGenome &sis=DYN_CAST(GAListGenome &, *c1); sis.GAList::copy(mom); GAListIter diter(dad); // Cycle through mom & dad to get the cyclic part of the crossover. mask[0] = 1; diter.head(); while(*diter.current() != *sis.head()){ for(i=0; i &bro=DYN_CAST(GAListGenome &, *c2); bro.GAList::copy(dad); GAListIter miter(mom); // Cycle through mom & dad to get the cyclic part of the crossover. mask[0] = 1; miter.head(); while(*miter.current() != *bro.head()){ for(i=0; i #include /* ---------------------------------------------------------------------------- ListGenome ------------------------------------------------------------------------------- ---------------------------------------------------------------------------- */ template class GAListGenome : public GAList, public GAGenome { public: GADeclareIdentity(); static int DestructiveMutator(GAGenome &, float); static int SwapMutator(GAGenome &, float); static float NodeComparator(const GAGenome&, const GAGenome&); static int OnePointCrossover(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*); static int PartialMatchCrossover(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*); static int OrderCrossover(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*); static int CycleCrossover(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*); public: GAListGenome(GAGenome::Evaluator f=0, void * u=(void *)0); GAListGenome(const GAListGenome &); GAListGenome & operator=(const GAGenome & orig) {copy(orig); return *this;} virtual ~GAListGenome(); virtual GAGenome *clone(GAGenome::CloneMethod flag=CONTENTS) const; virtual void copy(const GAGenome &); #ifdef GALIB_USE_STREAMS virtual int write (STD_OSTREAM &) const; #endif virtual int equal(const GAGenome & c) const; // Here we do inlined versions of the access members of the super class. We // do our own here so that we can set/unset the _evaluated flag appropriately. int destroy() { _evaluated = gaFalse; return GAList::destroy(); } int swap(unsigned int i, unsigned int j) { _evaluated = gaFalse; return GAList::swap(i,j); } T * remove() { _evaluated = gaFalse; return GAList::remove(); } int insert(GAList * t, GAListBASE::Location where=GAListBASE::AFTER) { _evaluated = gaFalse; return GAList::insert(t, where); } int insert(const T & t, GAListBASE::Location where=GAListBASE::AFTER) { _evaluated = gaFalse; return GAList::insert(t, where); } }; #ifdef GALIB_USE_BORLAND_INST #include #endif #endif galib247/ga/GAMask.h0100644003643600364360000000241610573535473013310 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- binstr1.h mbwall 19apr95 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved ---------------------------------------------------------------------------- */ #ifndef _ga_mask_h_ #define _ga_mask_h_ #include #define GA_MASK_TYPE char class GAMask { public: GAMask() { _n=0; _mask=(GA_MASK_TYPE*)0; } GAMask(const GAMask& m) { _n=0; _mask=(GA_MASK_TYPE*)0; copy(m); } GAMask& operator=(const GAMask& m) { copy(m); return *this; } ~GAMask() { delete [] _mask; } void copy(const GAMask& m) { size(m.size()); memcpy(_mask, m._mask, _n*sizeof(GA_MASK_TYPE)); } void clear() { memset(_mask, 0, _n*sizeof(GA_MASK_TYPE)); } int size() const {return _n;} int size(unsigned int s){ if(s > _n){ _n = s; delete [] _mask; _mask = new GA_MASK_TYPE [_n]; } return _n; } GA_MASK_TYPE mask(unsigned int i) const { return _mask[i]; } GA_MASK_TYPE & mask(unsigned int i) { return _mask[i]; } GA_MASK_TYPE operator[] (unsigned int i) const { return _mask[i]; } GA_MASK_TYPE & operator[] (unsigned int i) { return _mask[i]; } protected: GA_MASK_TYPE * _mask; unsigned int _n; }; #endif galib247/ga/GANode.h0100644003643600364360000000717210573535473013306 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- node.h mbwall 25nov94 Copyright 1995 Massachusetts Institute of Technology DESCRIPTION: This defines the node objects. ---------------------------------------------------------------------------- */ #ifndef _ga_node_h_ #define _ga_node_h_ #include #include /* ---------------------------------------------------------------------------- GANodeBASE ------------------------------------------------------------------------------- This is the basic node object. In its basic form it should be useful for trees, lists, and some graphs. I debated whether to make two different objects for tree and list nodes, but decided for now to make them the same. ---------------------------------------------------------------------------- */ struct GANodeBASE { GANodeBASE *next, *prev, *parent, *child; GANodeBASE() {next=0; prev=0; parent=0; child=0;} GANodeBASE(GANodeBASE *n, GANodeBASE *p, GANodeBASE *par, GANodeBASE *chi) {next=n; prev=p; parent=par; child=chi;} virtual ~GANodeBASE() {} }; #ifdef GALIB_USE_STREAMS inline STD_OSTREAM & operator<<(STD_OSTREAM & os, GANodeBASE & arg){ os << " node: " << &arg << "\n"; os << " next: " << arg.next << "\n"; os << " prev: " << arg.prev << "\n"; os << " child: " << arg.child << "\n"; os << " parent: " << arg.parent << "\n"; return(os); } #endif /* ---------------------------------------------------------------------------- GANode ------------------------------------------------------------------------------- This node is a container for any kind of object you want to put into a list. Since it is a sub-class of the BASE node object, it inherits all of the next, prev, etc members of that class. All we add here is support for the type- specific contents. Beware of what you put in for the type. Remember that it can be expensive to use an object rather than a pointer (if you have big objects, for example). We define this template using the object rather than a pointer so that it can be use for ints, chars, or other small objects. If you are going to contain a large object, you should instantiate it as a pointer to the object, not the object itself. Note also that we use the copy constructor to intialize the object rather than doing an assignment! This assumes that the object you put into this container has a properly functioning copy initializer and avoids the default construction followed by assignment that you'd get with operator=. You must have a copy creator defined for any object that goes into the nodes. The operator= must defined as well (it is used when the node contents get reassigned). We do not allow the nodes to be created without any arguments. Summary of methods your object must have: copy initializer operator= The node always owns its contents; when the node is destroyed, the contents of the node get destroyed as well. ---------------------------------------------------------------------------- */ template struct GANode : public GANodeBASE { T contents; // GANode() : GANodeBASE(), contents() {} GANode(const T & t) : GANodeBASE(), contents(t) {} virtual ~GANode() {} T & operator()(const T & t){contents = t; return contents;} }; #ifdef GALIB_USE_STREAMS template STD_OSTREAM & operator<<(STD_OSTREAM & os, GANode & arg){ os << " node: " << &arg << "\n"; os << " next: " << arg.next << "\n"; os << " prev: " << arg.prev << "\n"; os << " child: " << arg.child << "\n"; os << " parent: " << arg.parent << "\n"; return(os); } #endif #endif galib247/ga/GAParameter.C0100644003643600364360000004033010573535474014266 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- parameters.C mbwall 28jul94 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved DESCRIPTION: Definition of the parameter object and a container list for it. I did this as a separate list implementation because I don't want all of the overhead of a fullblown list. The parameter list is a special purpose, stripped down list implementation. ---------------------------------------------------------------------------- */ #include #include #include #include #include #include #define PRM_CHUNKSIZE 10 #define BUFSIZE 1024 // size of buffer for reading pairs #define MAX_PAIRS 5000 // max number of name-value pairs in stream #define NAMESIZE 128 // max length of name in name-value pair extern char _gaerrbuf1[]; extern char _gaerrbuf2[]; static int IsNumeric(const char*); GAParameter::GAParameter(const char* fn, const char* sn, Type tp, const void* v){ if(fn){ fname = new char[strlen(fn)+1]; strcpy(fname, fn); } else fname = (char*)0; if(sn){ sname = new char[strlen(sn)+1]; strcpy(sname, sn); } else sname = (char*)0; t = tp; memset(&val, 0, sizeof(Value)); setvalue(v); } GAParameter::GAParameter(const GAParameter& orig){ fname=sname = (char*)0; memset(&val, 0, sizeof(Value)); copy(orig); } void GAParameter::copy(const GAParameter& orig){ if(&orig == this) return; delete [] fname; delete [] sname; if(orig.fname){ fname = new char[strlen(orig.fname)+1]; strcpy(fname, orig.fname); } else fname = (char *)0; if(orig.sname){ sname = new char[strlen(orig.sname)+1]; strcpy(sname, orig.sname); } else sname = (char *)0; t = orig.t; setvalue(orig.value()); // do this directly... } GAParameter::~GAParameter(){ delete [] fname; delete [] sname; if(t == STRING) delete [] val.sval; } void GAParameter::setvalue(const void* v){ switch(t){ case BOOLEAN: case INT: val.ival = *((int*)v); break; case CHAR: val.cval = *((char*)v); break; case STRING: if(v != val.sval) { char* ptr=0; if(strlen((char*)v) > 0){ ptr = new char[strlen((char*)v)+1]; strcpy(ptr, (char*)v); } delete [] val.sval; val.sval = ptr; } break; case FLOAT: val.fval = *((float*)v); break; case DOUBLE: val.dval = *((double*)v); break; case POINTER: default: val.pval = v; break; } } // The default parameter list is empty. Allocate space for the pointers, but // don't allocate any parameters at this point. GAParameterList::GAParameterList(){ N = n = cur = 0; p = (GAParameter**)0; } GAParameterList::GAParameterList(const GAParameterList& list){ N = list.N; n = list.n; cur = list.cur; p = new GAParameter * [N]; for(unsigned int i=0; ifullname()) == 0 || strcmp(name, p[i]->shrtname()) == 0){ p[i]->value(v); found = 1; } } return found ? 0 : -1; } // Must do a special case for double/float. Any floats that get passed to this // routine will be cast to doubles, but then we need to force them back to a // float if FLOAT is the type that is expected. Kind of sucks, eh? // We could check the parameter type against the type here, but we don't. // (could do it for all of the 'set' members). Maybe in a later release. int GAParameterList::set(const char* name, double v) { int found = 0; for(unsigned int i=0; ifullname()) == 0 || strcmp(name, p[i]->shrtname()) == 0){ if(p[i]->type() == GAParameter::FLOAT){ float fval = (float)v; p[i]->value((void*)&fval); } else if(p[i]->type() == GAParameter::DOUBLE) p[i]->value((void*)&v); else GAErr(GA_LOC, "GAParameterList", "set", gaErrBadTypeIndicator); found = 1; } } return found ? 0 : -1; } // This allocates space for strings, so be sure to free it! int GAParameterList::get(const char* name, void* value) const { int status = 1; for(unsigned int i=0; ifullname()) == 0 || strcmp(name, p[i]->shrtname()) == 0){ switch(p[i]->type()){ case GAParameter::BOOLEAN: case GAParameter::INT: *((int*)value) = *((int*)p[i]->value()); break; case GAParameter::CHAR: *((char*)value) = *((char*)p[i]->value()); break; case GAParameter::STRING: break; case GAParameter::FLOAT: *((float*)value) = *((float*)p[i]->value()); break; case GAParameter::DOUBLE: *((double*)value) = *((double*)p[i]->value()); break; case GAParameter::POINTER: default: break; } status = 0; } } return status; } // Add the item to the list if it does not already exist. Return 0 if the add // was OK, -1 if there was a problem. int GAParameterList::add(const char* fn, const char* sn, GAParameter::Type t, const void* v) { int status = -1; if(n == N){ N += PRM_CHUNKSIZE; GAParameter **tmp = p; p = new GAParameter* [N]; memcpy(p, tmp, n * sizeof(GAParameter*)); delete [] tmp; } int found = 0; for(unsigned int i=0; ifullname()) == 0 && strcmp(sn, p[i]->shrtname()) == 0) found = 1; } if(!found){ cur = n; p[n++] = new GAParameter(fn, sn, t, v); } return status; } // When you remove a parameter from the list, the iterator is left pointing // at the same location. If the item was the last in the list, then the // iterator moves to the new last item in the list. // Return 0 if everything was OK, -1 if error. int GAParameterList::remove(){ int status = -1; if(cur > n) return status; delete p[cur]; memmove(&(p[cur]), &(p[cur+1]), (n-cur-1)*sizeof(GAParameter*)); n--; if(cur > n) cur = n; status = 0; return status; } GAParameter* GAParameterList::operator()(const char* name){ for(unsigned int i=0; ifullname())==0 || strcmp(name, p[i]->shrtname())==0) return p[i]; return (GAParameter*)0; } #ifdef GALIB_USE_STREAMS // Dump the parameters to the specified stream. Just name-value pairs with a // tab delimiter and newline separating pairs. // If there is an error, return 1, otherwise return 0. int GAParameterList::write(STD_OSTREAM& os) const { for(unsigned int i=0; ifullname() << "\t"; switch(p[i]->type()){ case GAParameter::BOOLEAN: ival = *((int*)(p[i]->value())); if(ival) os << "1\n"; else os << "0\n"; break; case GAParameter::INT: ival = *((int*)(p[i]->value())); os << ival << "\n"; break; case GAParameter::CHAR: cval = *((char*)(p[i]->value())); os << cval << "\n"; break; case GAParameter::STRING: sval = ((char*)(p[i]->value())); os << sval << "\n"; break; case GAParameter::FLOAT: fval = *((float*)(p[i]->value())); os << fval << "\n"; break; case GAParameter::DOUBLE: dval = *((double*)(p[i]->value())); os << dval << "\n"; break; case GAParameter::POINTER: default: os << "(pointer)\n"; // os << p[i]->value() << "\n"; break; } } return 0; } int GAParameterList::write(const char* filename) const { STD_OFSTREAM outfile(filename, (STD_IOS_OUT | STD_IOS_TRUNC)); // should be done this way, but SGI systems (and others?) don't do it right... // if(! outfile.is_open()){ if(outfile.fail()){ GAErr(GA_LOC, "GAParameterList", "write", gaErrWriteError, filename); return 1; } int status = write(outfile); outfile.close(); return status; } // Read name-value pairs from the stream. If the first item is a number, then // we expect that many name-value pairs. If not, then we read until the end of // the stream. Be sure not to duplicate the last one, and be sure to dump any // items from a # to end-of-line. // Parse for name-value pairs, where the pairs are separated by whitespace. // *Every* parameter must be specified as a name-value pair (no single name // with no value allowed). If we get a single name with no value that will // screw up the name-value pairing for any remaining pairs. We could check for // this situation, but for now we just let it happen and dump the errors. (i'll // do a better parsing algorithm at some later point). // We return the number of items that we were able to read from the stream. // If we come across an item that is unrecognized, we dump an error message. // The buffer length is limited here, so don't try to read in any really long // lines. // We parse only for items that we know about - if we come across a pair // whose name we do not know about, we ignore the pair and go on to the next. // There's no global list to tell us what type things are, and we don't assume. // We don't allow setting pointers using this method. int GAParameterList::read(STD_ISTREAM& is, GABoolean flag){ int nfound = 0; if(n == 0) return nfound; char buf[BUFSIZE]; char name[NAMESIZE]; int toggle = 0, count = 0, npairs = -1; is.width(sizeof(buf)); // don't allow to overrun buffer do{ is >> buf; if(npairs == -1){ if(IsNumeric(buf)){ npairs = atoi(buf); is >> buf; } else{ npairs = MAX_PAIRS; } } if(is.eof()){ break; } else if(buf[0] == '#'){ // dump to end-of-line is.get(buf, BUFSIZE); // fails on lines longer than BUFSIZE } else if(toggle == 0){ strcpy(name, buf); toggle = 1; } else if(toggle == 1){ int found = 0; count += 1; toggle = 0; for(unsigned int i=0; ifullname()) == 0 || strcmp(name, p[i]->shrtname()) == 0){ found = 1; int ival; float fval; double dval; switch(p[i]->type()){ case GAParameter::BOOLEAN: case GAParameter::INT: ival = atoi(buf); set(name, (void*)&ival); nfound += 1; break; case GAParameter::CHAR: case GAParameter::STRING: set(name, (void*)buf); nfound += 1; break; case GAParameter::FLOAT: fval = (float)atof(buf); set(name, (void*)&fval); nfound += 1; break; case GAParameter::DOUBLE: dval = (double)atof(buf); set(name, (void*)&dval); nfound += 1; break; case GAParameter::POINTER: default: break; } // Move this parameter to the front of the list // if(i > 0) { // GAParameter *tmpptr = p[i]; // memmove(&(p[1]), &(p[0]), i * sizeof(GAParameter*)); // p[0] = tmpptr; // } if(i < n-1) { GAParameter *tmpptr = p[i]; memmove(&(p[i]), &(p[i+1]), (n-i-1) * sizeof(GAParameter*)); p[n-1] = tmpptr; } } } if(!found && flag == gaTrue){ strcpy(_gaerrbuf1, ""); strcat(_gaerrbuf1, "unrecognized variable name '"); strcat(_gaerrbuf1, name); strcat(_gaerrbuf1, "'"); GAErr(GA_LOC, "GAParameterList", "read", _gaerrbuf1); } } } while(!is.eof() && count < npairs); if(toggle == 1){ strcpy(_gaerrbuf1, ""); strcat(_gaerrbuf1, "variable "); strcat(_gaerrbuf1, name); strcat(_gaerrbuf1, " has no value"); strcat(_gaerrbuf2, "be sure there is a newline at end of the file"); GAErr(GA_LOC, "GAParameterList", "read", _gaerrbuf1, _gaerrbuf2); is.clear(STD_IOS_BADBIT | is.rdstate()); } return nfound; } int GAParameterList::read(const char* filename, GABoolean flag){ STD_IFSTREAM infile(filename, STD_IOS_IN); if(!infile){ GAErr(GA_LOC, "GAParameterList", "read", gaErrReadError, filename); return 1; } int status = read(infile, flag); infile.close(); return status; } #endif // Parse the arglist for any recognized arguments. If we find a string we // know, then we set the value. If we find a string we don't know then we // don't do anything unless the flag is set. If the flag is set then we // complain about unknown arguments. // You should set up the list before you do the parsing in order to grab // arguments from the arglist. // When we encounter names we know with valid values, we put the list into // order as we get the new values. When we recognize a pair, we pull the // parameter from the list, set its value, then stick it at the end of the // parameter list. So if something turns up more than once, we'll remove- // then-append it more than once and the ordering from argv will be properly // maintained. // We assume that argv[0] is the name of the program, so we don't barf on // it if it is not a recognized name. int GAParameterList::parse(int& argc, char *argv[], GABoolean flag){ int nfound = 0; if(n == 0) return nfound; char **argvout = new char* [argc]; int argcu = argc-1; int argcl = 0; for(int i=0; ishrtname(), argv[i]) == 0 || strcmp(p[j]->fullname(), argv[i]) == 0){ found = 1; argvout[argcu] = argv[i]; argcu--; if(++i >= argc){ GAErr(GA_LOC, argv[0], argv[i-1], " needs a value"); } else{ int ival; float fval; double dval; switch(p[j]->type()){ case GAParameter::BOOLEAN: if(IsNumeric(argv[i])){ ival = atoi(argv[i]); ival = (ival == 0) ? 0 : 1; } else { if(strcmp(argv[i], "true") == 0 || strcmp(argv[i], "True") == 0 || strcmp(argv[i], "TRUE") == 0 || strcmp(argv[i], "t") == 0 || strcmp(argv[i], "T") == 0) ival = 1; } set(argv[i-1], (void*)&ival); nfound += 1; break; case GAParameter::INT: ival = atoi(argv[i]); set(argv[i-1], (void*)&ival); nfound += 1; break; case GAParameter::CHAR: case GAParameter::STRING: set(argv[i-1], (void*)argv[i]); nfound += 1; break; case GAParameter::FLOAT: fval = (float)atof(argv[i]); set(argv[i-1], (void*)&fval); nfound += 1; break; case GAParameter::DOUBLE: dval = (double)atof(argv[i]); set(argv[i-1], (void*)&dval); nfound += 1; break; case GAParameter::POINTER: default: break; } // Move this parameter to the front of the list // if(j > 0) { // GAParameter *tmpptr = p[j]; // memmove(&(p[1]), &(p[0]), j * sizeof(GAParameter*)); // p[0] = tmpptr; // } if(j < n-1) { GAParameter *tmpptr = p[j]; memmove(&(p[j]), &(p[j+1]), (n-j-1) * sizeof(GAParameter*)); p[n-1] = tmpptr; } // Now update the argv array and argc count to indicate we understood this one argvout[argcu] = argv[i]; argcu--; continue; } } } if(!found){ if(flag && i!=0){ _gaerrbuf1[0] = '\0'; strcat(_gaerrbuf1, "unrecognized name "); strcat(_gaerrbuf1, argv[i]); GAErr(GA_LOC, "GAParameterList", "parse", _gaerrbuf1); } argvout[argcl] = argv[i]; argcl++; } } // bcopy(argvout, argv, argc * sizeof(char*)); memcpy(argv, argvout, argc*sizeof(char*)); argc = argcl; delete [] argvout; return nfound; } static int IsNumeric(const char* str){ for(int i=strlen(str)-1; i>=0; i--) if(! isdigit(str[i]) && str[i] != '.') return 0; return 1; } galib247/ga/GAParameter.h0100644003643600364360000000731410573535473014337 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- parameters.h mbwall 14jul95 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved DESCRIPTION: Header for the parameters object used by the GA objects. ---------------------------------------------------------------------------- */ #ifndef _ga_parameters_h_ #define _ga_parameters_h_ #include #include #include /* ---------------------------------------------------------------------------- This object is used for naming the parameters. We associate a fullname, a short name, and a value with each parameter. ---------------------------------------------------------------------------- */ class GAParameter { public: enum Type {BOOLEAN, CHAR, STRING, INT, FLOAT, DOUBLE, POINTER}; public: GAParameter(const char* fn, const char* sn, Type tp, const void* v); GAParameter(const GAParameter& orig); GAParameter& operator=(const GAParameter& orig){ copy(orig); return *this; } virtual ~GAParameter(); void copy(const GAParameter&); char* fullname() const { return fname; } char* shrtname() const { return sname; } const void* value() const { return (t==STRING ? val.sval : (t==POINTER ? val.pval : &val)); } const void* value(const void* v) {setvalue(v); return(t==STRING ? val.sval : (t==POINTER ? val.pval:&val));} Type type() const { return t; } protected: char* fname; char* sname; union Value { int ival; char cval; char* sval; float fval; double dval; const void* pval; } val; Type t; void setvalue(const void*); }; /* ---------------------------------------------------------------------------- The parameter list is implemented as an array, but has the interface of a list. Don't ask. You can traverse through the list to get the parameters that you need. Be sure to check the type before you try to extract the value for any specific parameter in the list. ---------------------------------------------------------------------------- */ class GAParameterList { public: GAParameterList(); GAParameterList(const GAParameterList&); GAParameterList& operator=(const GAParameterList&); virtual ~GAParameterList(); int size() const { return n; } int get(const char*, void*) const; int set(const char*, const void*); int set(const char* s, int v) { return set(s, (void*)&v); } int set(const char* s, unsigned int v) { return set(s, (void*)&v); } int set(const char* s, char v) { return set(s, (void*)&v); } int set(const char* s, const char* v) { return set(s, (void*)v); } int set(const char* s, double v); int add(const char*, const char*, GAParameter::Type, const void*); int remove(); GAParameter& operator[](unsigned int i) const {return *(p[i]);} GAParameter& next(){return *(p[((cur > n) ? cur=0 : ++cur)]);} GAParameter& prev(){return *(p[((cur == 0) ? cur=n-1 : --cur)]);} GAParameter& current() const {return *(p[cur]);} GAParameter& first(){return *(p[cur=0]);} GAParameter& last(){return *(p[cur=n-1]);} GAParameter* operator()(const char* name); int parse(int& argc, char **argv, GABoolean flag=gaTrue); #ifdef GALIB_USE_STREAMS int write(const char* filename) const; int write(STD_OSTREAM & os) const; int read(const char* filename, GABoolean flag=gaTrue); int read(STD_ISTREAM & is, GABoolean flag=gaTrue); #endif protected: unsigned int n, N, cur; GAParameter **p; }; #ifdef GALIB_USE_STREAMS inline STD_OSTREAM & operator<< (STD_OSTREAM &os, const GAParameterList& plist) { plist.write(os); return os; } inline STD_ISTREAM & operator>> (STD_ISTREAM& is, GAParameterList& plist) { plist.read(is); return is; } #endif #endif galib247/ga/GAPopulation.C0100644003643600364360000005760210573535474014512 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- population.C mbwall 11aug94 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved ---------------------------------------------------------------------------- */ #include #include #include #include #include #include // for the sake of flaky g++ compiler // windows is promiscuous in its use of min/max, and that causes us grief. so // turn of the use of min/max macros in this file. thanks nick wienholt #if !defined(NOMINMAX) #define NOMINMAX #endif // This is the default population initializer. It simply calls the initializer // for each member of the population. Then we touch the population to tell it // that it needs to update stats and/or sort (but we don't actually force // either one to occur. // The population object takes care of setting/unsetting the status flags. void GAPopulation::DefaultInitializer(GAPopulation & p){ for(int i=0; iassign(*this); sclscm = new DEFAULT_SCALING; evaldata = (GAEvalData*)0; ga = (GAGeneticAlgorithm*)0; } GAPopulation::GAPopulation(const GAGenome & c, unsigned int popsize) { csz = N = GA_POP_CHUNKSIZE; n = (popsize < 1 ? 1 : popsize); while(N < n) N += csz; rind = new GAGenome * [N]; sind = new GAGenome * [N]; for(unsigned int i=0; iassign(*this); sclscm = new DEFAULT_SCALING; evaldata = (GAEvalData*)0; ga = (GAGeneticAlgorithm*)0; } GAPopulation::GAPopulation(const GAPopulation & orig){ n = N = 0; rind = sind = (GAGenome**)0; indDiv = (float*)0; sclscm = (GAScalingScheme*)0; slct = (GASelectionScheme*)0; evaldata = (GAEvalData*)0; copy(orig); } GAPopulation::~GAPopulation(){ for(unsigned int i=0; iclone(); sind = new GAGenome * [N]; memcpy(sind, rind, N * sizeof(GAGenome*)); if(arg.indDiv) { indDiv = new float[N*N]; memcpy(indDiv, arg.indDiv, (N*N*sizeof(float))); } else { indDiv = 0; } sclscm = arg.sclscm->clone(); scaled = gaFalse; if(arg.scaled == gaTrue) scale(); slct = arg.slct->clone(); slct->assign(*this); selectready = gaFalse; if(arg.selectready == gaTrue) prepselect(); if(arg.evaldata) evaldata = arg.evaldata->clone(); else evaldata = (GAEvalData*)0; neval = 0; // don't copy the evaluation count! rawSum = arg.rawSum; rawAve = arg.rawAve; rawMax = arg.rawMax; rawMin = arg.rawMin; rawVar = arg.rawVar; rawDev = arg.rawDev; popDiv = arg.popDiv; fitSum = arg.fitSum; fitAve = arg.fitAve; fitMax = arg.fitMax; fitMin = arg.fitMin; fitVar = arg.fitVar; fitDev = arg.fitDev; sortorder = arg.sortorder; rsorted = arg.rsorted; ssorted = gaFalse; // we must sort at some later point statted = arg.statted; evaluated = arg.evaluated; divved = arg.divved; init = arg.init; eval = arg.eval; ud = arg.ud; ga = arg.ga; } // Resize the population. If we shrink, we delete the extra genomes. If // we grow, we clone new ones (and we DO NOT initialize them!!!). When we // trash the genomes, we delete the worst of the population! We do not // free up the space used by the array of pointers, but we do free up the // space used by the genomes. // We do a clone of the genome contents so that we don't have to initialize // the new ones (what if the population has a custom initilizer?). We randomly // pick which ones to clone from the existing individuals. If the population // contains no genomes, then we post an error message (since there are no // individuals from which to clone the new ones). // If the population was evaluated, then we evaluate the new genomes. We // do not sort nor restat the population, and we tag the statted and sorted // flags to reflect the fact that they are no longer valid. // Resizing to a bigger size is the same as a batch 'add' int GAPopulation::size(unsigned int popsize){ if(popsize == n) return n; if(n == 0 && popsize > 0) { GAErr(GA_LOC, "GAPopuluation", "size", gaErrNoIndividuals); return n; } if(popsize > n){ grow(popsize); for(unsigned int i=n; iclone(GAGenome::CONTENTS); rsorted = gaFalse; } else{ for(unsigned int i=popsize; irind, 0, n-1); else GAPopulation::QuickSortDescendingRaw(This->rind, 0, n-1); This->selectready = gaFalse; } This->rsorted = gaTrue; } else if(basis == SCALED){ if(ssorted == gaFalse || flag == gaTrue){ if(sortorder == LOW_IS_BEST) GAPopulation::QuickSortAscendingScaled(This->sind, 0, n-1); else GAPopulation::QuickSortDescendingScaled(This->sind, 0, n-1); This->selectready = gaFalse; } This->ssorted = gaTrue; } } // Evaluate each member of the population and store basic population statistics // in the member variables. It is OK to run this on a const object - it // changes to physical state of the population, but not the logical state. // The partial sums are normalized to the range [0,1] so that they can be // used whether the population is sorted as low-is-best or high-is-best. // Individual 0 is always the best individual, and the partial sums are // calculated so that the worst individual has the smallest partial sum. All // of the partial sums add to 1.0. void GAPopulation::statistics(GABoolean flag) const { if(statted == gaTrue && flag != gaTrue) return; GAPopulation * This = (GAPopulation *)this; if(n > 0) { float tmpsum; This->rawMin = This->rawMax = tmpsum = rind[0]->score(); unsigned int i; for(i=1; iscore(); tmpsum += scr; This->rawMax = GAMax(rawMax, scr); This->rawMin = GAMin(rawMin, scr); } float tmpave = tmpsum / n; This->rawAve = tmpave; This->rawSum = tmpsum; // if scores are huge we'll lose data here float tmpvar = 0.0; if(n > 1){ for(i=0; iscore() - This->rawAve; s *= s; tmpvar += s; } tmpvar /= (n-1); } This->rawDev = (float)sqrt(tmpvar); This->rawVar = tmpvar; // could lose data if huge variance } else { This->rawMin = This->rawMax = This->rawSum = 0.0; This->rawDev = This->rawVar = 0.0; } This->statted = gaTrue; } // Do the scaling on the population. Like the statistics and diversity, this // method does not change the contents of the population, but it does change // the values of the status members of the object. So we allow it to work on // a const population. void GAPopulation::scale(GABoolean flag) const { if(scaled == gaTrue && flag != gaTrue) return; GAPopulation* This = (GAPopulation*)this; if(n > 0) { sclscm->evaluate(*This); float tmpsum; This->fitMin = This->fitMax = tmpsum = sind[0]->fitness(); unsigned int i; for(i=1; ifitness(); This->fitMax = GAMax(fitMax, sind[i]->fitness()); This->fitMin = GAMin(fitMin, sind[i]->fitness()); } float tmpave = tmpsum / n; This->fitAve = tmpave; This->fitSum = tmpsum; // if scores are huge we'll lose data here float tmpvar = 0.0; if(n > 1){ for(i=0; ifitness() - This->fitAve; s *= s; tmpvar += s; } tmpvar /= (n-1); } This->fitDev = (float)sqrt(tmpvar); This->fitVar = tmpvar; // could lose data if huge variance } else { This->fitMin = This->fitMax = This->fitSum = 0.0; This->fitVar = This->fitDev = 0.0; } This->scaled = gaTrue; This->ssorted = gaFalse; } // Calculate the population's diversity score. The matrix is triangular and // we don't have to calculate the diagonals. This assumes that div(i,j) is // the same as div(j,i) (for our purposes this will always be true, but it is // possible for someone to override some of the individuals in the population // and not others). // For now we keep twice as many diversity numbers as we need. We need only // n*(n-1)/2, but I can't seem to figure out an efficient way to map i,j to the // reduced n*(n-1)/2 set (remember that the diagonals are always 0.0). // The diversity of the entire population is just the average of all the // individual diversities. So if every individual is completely different from // all of the others, the population diversity is > 0. If they are all the // same, the diversity is 0.0. We don't count the diagonals for the population // diversity measure. 0 means minimal diversity means all the same. void GAPopulation::diversity(GABoolean flag) const { if(divved == gaTrue && flag != gaTrue) return; GAPopulation* This = (GAPopulation*)this; if(n > 1) { if(This->indDiv == 0) This->indDiv = new float[N*N]; This->popDiv = 0.0; for(unsigned int i=0; iindDiv[i*n+i] = 0.0; for(unsigned int j=i+1; jindDiv[j*n+i] = This->indDiv[i*n+j] = individual(i).compare(individual(j)); This->popDiv += indDiv[i*n+j]; } } This->popDiv /= n*(n-1)/2; } else { This->popDiv = 0.0; } This->divved = gaTrue; } void GAPopulation::prepselect(GABoolean flag) const { if(selectready == gaTrue && flag != gaTrue) return; GAPopulation* This = (GAPopulation*)this; This->slct->update(); This->selectready = gaTrue; } // Return a reference to the scaling object. GAScalingScheme & GAPopulation::scaling(const GAScalingScheme& s){ delete sclscm; sclscm = s.clone(); scaled = gaFalse; return *sclscm; } // Return a reference to the selection object. GASelectionScheme& GAPopulation::selector(const GASelectionScheme& s) { delete slct; slct = s.clone(); slct->assign(*this); selectready = gaFalse; return *slct; } // Replace the specified genome with the one that is passed to us then // return the one that got replaced. Use the replacement flags to determine // which genome will be replaced. If we get a genome as the second // argument, then replace that one. If we get a NULL genome, then we // return a NULL and don't do anything. // If the population is sorted, then we maintain the sort by doing a smart // replacement. // If the population is not sorted, then we just do the replacement without // worrying about the sort. Replace best and worst both require that we know // which chromsomes are which, so we do a sort before we do the replacement, // then we do a smart replacement. // In both cases we flag the stats as out-of-date, but we do not update the // stats. Let that happen when it needs to happen. // If which is < 0 then it is a flag that tells us to do a certain kind of // replacement. Anything non-negative is assumed to be an index to a // genome in the population. // This does not affect the state of the evaluated member - it assumes that // the individual genome has a valid number for its score. GAGenome * GAPopulation::replace(GAGenome * repl, int which, SortBasis basis) { int i=-1; GAGenome * orig=(GAGenome *)0; if(repl == (GAGenome *)0) return orig; switch(which){ case BEST: sort(gaFalse, basis); i = 0; break; case WORST: sort(gaFalse, basis); i = n-1; break; case RANDOM: i = GARandomInt(0, n-1); break; default: if(0 <= which && which < (int)n) i = which; break; } if(i >= 0){ // We could insert this properly if the population is sorted, but that would // require us to evaluate the genome, and we don't want to do that 'cause that // will screw up any parallel implementations. So we just stick it in the // population and let the sort take care of it at a later time as needed. if(basis == RAW){ orig = rind[i]; // keep the original to return at the end rind[i] = repl; memcpy(sind, rind, N * sizeof(GAGenome*)); } else{ orig = sind[i]; // keep the original to return at the end sind[i] = repl; memcpy(rind, sind, N * sizeof(GAGenome*)); } rsorted = ssorted = gaFalse; // must sort again // flag for recalculate stats statted = gaFalse; // Must flag for a new evaluation. evaluated = gaFalse; // No way to do incremental update of scaling info since we don't know what the // scaling object will do. scaled = gaFalse; // *** should do an incremental update of the diversity here so we don't // recalculate all of the diversities when only one is updated divved = gaFalse; // selector needs update selectready = gaFalse; // make sure the genome has the correct genetic algorithm pointer if(ga) repl->geneticAlgorithm(*ga); } return orig; } // Replace the genome o in the population with the genome r. Return a // pointer to the original genome, o. This assumes that o exists in the // population. If it does not, we return a NULL. If the genomes are the // same, do nothing and return a pointer to the genome. GAGenome * GAPopulation::replace(GAGenome * r, GAGenome * o) { GAGenome * orig=(GAGenome *)0; if(r == (GAGenome *)0 || o == (GAGenome *)0) return orig; if(r == o) return r; unsigned int i; for(i=0; i= (int)n) return removed; if(basis == RAW){ removed = rind[i]; memmove(&(rind[i]), &(rind[i+1]), (n-i-1)*sizeof(GAGenome *)); memcpy(sind, rind, N * sizeof(GAGenome*)); ssorted = gaFalse; } else if(basis == SCALED){ removed = sind[i]; memmove(&(sind[i]), &(sind[i+1]), (n-i-1)*sizeof(GAGenome *)); memcpy(rind, sind, N * sizeof(GAGenome*)); rsorted = gaFalse; } else return removed; n--; evaluated = gaFalse; // *** should be smart about these and do incremental update? scaled = statted = divved = selectready = gaFalse; return removed; } // Remove the specified genome from the population. If the genome is // not in the population, we return NULL. We do a linear search here (yuk for // large pops, but little else we can do). The memory used by the genome is // now the responsibility of the caller. GAGenome * GAPopulation::remove(GAGenome * r) { GAGenome * removed=(GAGenome *)0; if(r == (GAGenome *)0) return removed; unsigned int i; for(i=0; igeneticAlgorithm(*ga); n++; rsorted = ssorted = gaFalse; // may or may not be true, but must be sure evaluated = scaled = statted = divved = selectready = gaFalse; return c; } GAGeneticAlgorithm * GAPopulation::geneticAlgorithm(GAGeneticAlgorithm& g){ for(unsigned int i=0; igeneticAlgorithm(g); return(ga = &g); } #ifdef GALIB_USE_STREAMS void GAPopulation::write(STD_OSTREAM & os, SortBasis basis) const { for(unsigned int i=0; i l){ v = c[r]->score(); i = l-1; j = r; for(;;){ while(c[++i]->score() < v && i <= r); while(c[--j]->score() > v && j > 0); if(i >= j) break; t = c[i]; c[i] = c[j]; c[j] = t; } t = c[i]; c[i] = c[r]; c[r] = t; GAPopulation::QuickSortAscendingRaw(c,l,i-1); GAPopulation::QuickSortAscendingRaw(c,i+1,r); } } void GAPopulation::QuickSortDescendingRaw(GAGenome **c, int l, int r) { int i,j; float v; GAGenome *t; if(r > l){ v = c[r]->score(); i = l-1; j = r; for(;;){ while(c[++i]->score() > v && i <= r); while(c[--j]->score() < v && j > 0); if(i >= j) break; t = c[i]; c[i] = c[j]; c[j] = t; } t = c[i]; c[i] = c[r]; c[r] = t; GAPopulation::QuickSortDescendingRaw(c,l,i-1); GAPopulation::QuickSortDescendingRaw(c,i+1,r); } } void GAPopulation::QuickSortAscendingScaled(GAGenome **c, int l, int r) { int i,j; float v; GAGenome *t; if(r > l){ v = c[r]->fitness(); i = l-1; j = r; for(;;){ while(c[++i]->fitness() < v && i <= r); while(c[--j]->fitness() > v && j > 0); if(i >= j) break; t = c[i]; c[i] = c[j]; c[j] = t; } t = c[i]; c[i] = c[r]; c[r] = t; GAPopulation::QuickSortAscendingScaled(c,l,i-1); GAPopulation::QuickSortAscendingScaled(c,i+1,r); } } void GAPopulation::QuickSortDescendingScaled(GAGenome **c, int l, int r) { int i,j; float v; GAGenome *t; if(r > l){ v = c[r]->fitness(); i = l-1; j = r; for(;;){ while(c[++i]->fitness() > v && i <= r); while(c[--j]->fitness() < v && j > 0); if(i >= j) break; t = c[i]; c[i] = c[j]; c[j] = t; } t = c[i]; c[i] = c[r]; c[r] = t; GAPopulation::QuickSortDescendingScaled(c,l,i-1); GAPopulation::QuickSortDescendingScaled(c,i+1,r); } } galib247/ga/GAPopulation.h0100644003643600364360000002205410573535473014547 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- population.h mbwall 3aug94 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved DESCRIPTION: The population holds an array of pointers to genomes. It also keeps track of the fitness statistics for the genomes in the population. ---------------------------------------------------------------------------- */ #ifndef _ga_population_h_ #define _ga_population_h_ #include #include #include #include #include #include #ifdef max #undef max #endif #ifdef min #undef min #endif /* ---------------------------------------------------------------------------- size Use the size member function to get and set the size of the population. The population allocates space for genomes in chunks, so you can vary the chunksize as well if you are really tight for space. The compact member function will remove all extra pointers. If you shrink the population to 0 then you cannot use the 'size' method to make the population bigger. When resizing to a larger size, we clone randomly individuals from the existing population. sort The sort member is defined so that it can work on a const population. It does not change the logical state of the population, but it does change its physical state. We sort from best (0th individual) to worst (n-1). The sort figures out whether high is best or low is best. evaluate If you want to force an evaluation, pass gaTrue to the evaluate member function. Otherwise the population will use its internal state to determine whether or not it needs to do the evaluation. initialize This method determines how the population should be initialized. The default is to call the initializer for each genome. statistics Update the statistics. We do this only on-demand so that no unneeded calculations take place. diversity Like the statistics function, we call this one only on demand. This member function can be particularly expensive, especially for large populations. So we store the values and update them only as needed. The population diversity measure is the average of the individual measures (less the diagonal scores). ---------------------------------------------------------------------------- */ class GAPopulation : public GAID { public: GADefineIdentity("GAPopulation", GAID::Population); typedef void (*Initializer)(GAPopulation &); typedef void (*Evaluator)(GAPopulation &); static void DefaultInitializer(GAPopulation &); static void DefaultEvaluator(GAPopulation &); public: enum SortBasis { RAW, SCALED }; enum SortOrder { LOW_IS_BEST, HIGH_IS_BEST }; enum Replacement { BEST = -1, WORST = -2, RANDOM = -3 }; public: GAPopulation(); GAPopulation(const GAGenome & c, unsigned int psize=1); GAPopulation(const GAPopulation & arg); GAPopulation & operator=(const GAPopulation & arg){copy(arg); return(*this);} virtual ~GAPopulation(); virtual GAPopulation * clone() const {return new GAPopulation(*this);} virtual void copy(const GAPopulation & arg); int size() const { return n; } int size(unsigned int popsize); int chunksize() const { return csz; } int chunksize(unsigned int csize) { return csz=csize; } int compact(); void touch() { rsorted=ssorted=selectready=divved=statted=scaled=evaluated=gaFalse; } void statistics(GABoolean flag=gaFalse) const; void diversity(GABoolean flag=gaFalse) const; void scale(GABoolean flag=gaFalse) const; void prepselect(GABoolean flag=gaFalse) const; void sort(GABoolean flag=gaFalse, SortBasis basis=RAW) const; float sum() const {if(!statted) statistics(); return rawSum;} float ave() const {if(!statted) statistics(); return rawAve;} float var() const {if(!statted) statistics(); return rawVar;} float dev() const {if(!statted) statistics(); return rawDev;} float max() const {if(!statted) statistics(); return rawMax;} float min() const {if(!statted) statistics(); return rawMin;} float div() const {if(!divved) diversity(); return popDiv;} float div(unsigned int i, unsigned int j) const {if(!divved) diversity(); return indDiv[i*n+j];} float fitsum() const {if(!scaled) scale(); return fitSum;} float fitave() const {if(!scaled) scale(); return fitAve;} float fitmax() const {if(!scaled) scale(); return fitMax;} float fitmin() const {if(!scaled) scale(); return fitMin;} float fitvar() const {if(!scaled) scale(); return fitVar;} float fitdev() const {if(!scaled) scale(); return fitDev;} int nevals() const { return neval; } void evaluate(GABoolean flag=gaFalse) { if(evaluated == gaFalse || flag == gaTrue){ (*eval)(*this); neval++; scaled = statted = divved = rsorted = ssorted = gaFalse; } evaluated = gaTrue; } Evaluator evaluator() const {return eval;} Evaluator evaluator(Evaluator e) { evaluated = gaFalse; return eval=e; } void initialize() { neval = 0; (*init)(*this); touch(); } Initializer initializer() const {return init;} Initializer initializer(Initializer i) { return init=i; } SortOrder order() const { return sortorder; } SortOrder order(SortOrder flag); GAGenome & select() { if(!selectready) prepselect(); return slct->select(); } GASelectionScheme & selector() const { return *slct; } GASelectionScheme & selector(const GASelectionScheme&); GAScalingScheme & scaling() const { GAPopulation* This = (GAPopulation*)this; This->scaled=gaFalse; return *sclscm; } GAScalingScheme & scaling(const GAScalingScheme&); GAGeneticAlgorithm * geneticAlgorithm() const {return ga;} GAGeneticAlgorithm * geneticAlgorithm(GAGeneticAlgorithm&); void * userData() const {return ud;} void * userData(void * u){return(ud=u);} GAEvalData * evalData() const {return evaldata;} GAEvalData * evalData(const GAEvalData& o) {delete evaldata; evaldata = o.clone(); return evaldata;} GAGenome& best(unsigned int i=0, SortBasis basis=RAW) const { if(basis == SCALED) scale(); sort(gaFalse, basis); return ((basis == RAW) ? *(rind[i]) : *(sind[i])); } GAGenome& worst(unsigned int i=0, SortBasis basis=RAW) const { if(basis == SCALED) scale(); sort(gaFalse, basis); return ((basis == RAW) ? *(rind[n-1-i]) : *(sind[n-1-i])); } GAGenome& individual(unsigned int i, SortBasis basis=RAW) const { return ((basis == RAW) ? *(rind[i]) : *(sind[i])); } GAGenome * add(GAGenome *); GAGenome * add(const GAGenome&); GAGenome * remove(int which=WORST, SortBasis basis=RAW); GAGenome * remove(GAGenome *); GAGenome * replace(GAGenome *, int which=RANDOM, SortBasis basis=RAW); GAGenome * replace(GAGenome * newgenome, GAGenome * oldgenome); void destroy(int w=WORST, SortBasis b=RAW) { delete remove(w,b); } #ifdef GALIB_USE_STREAMS virtual void read(STD_ISTREAM &){} virtual void write (STD_OSTREAM & os, SortBasis basis=RAW) const; #endif protected: unsigned int neval; // number of evals since initialization unsigned int csz; // how big are chunks we allocate? unsigned int n, N; // how many are in the population, allocated SortOrder sortorder; // is best a high score or a low score? GABoolean rsorted; // are the individuals sorted? (raw) GABoolean ssorted; // are the individuals sorted? (scaled) GABoolean scaled; // has the population been scaled? GABoolean statted; // are the stats valid? GABoolean evaluated; // has the population been evaluated? GABoolean divved; // has the population diversity been measured? GABoolean selectready; // has the selector been updated? float rawSum, rawAve; // sum, ave of the population's objectives float rawMax, rawMin; // max, min of the population's objectives float rawVar, rawDev; // variance, standard deviation float popDiv; // overall population diversity [0,) float* indDiv; // table for genome similarities (diversity) GAGenome** rind; // the individuals of the population (raw) GAGenome** sind; // the individuals of the population (scaled) float fitSum, fitAve; // sum, ave of the population's fitness scores float fitMax, fitMin; // max, min of the population's fitness scores float fitVar, fitDev; // variance, standard deviation of fitness GAScalingScheme* sclscm; // scaling method GASelectionScheme* slct; // selection method Initializer init; // initialization method Evaluator eval; // population evaluation method void* ud; // pointer to user data GAGeneticAlgorithm* ga; // the ga that is using this population GAEvalData* evaldata; // data for evaluator to use (optional) int grow(unsigned int); static void QuickSortAscendingRaw(GAGenome**, int, int); static void QuickSortDescendingRaw(GAGenome**, int, int); static void QuickSortAscendingScaled(GAGenome**, int, int); static void QuickSortDescendingScaled(GAGenome**, int, int); }; #ifdef GALIB_USE_STREAMS inline STD_OSTREAM & operator<< (STD_OSTREAM & os, const GAPopulation & arg) { arg.write(os); return os; } inline STD_ISTREAM & operator>> (STD_ISTREAM & is, GAPopulation & arg) { arg.read(is); return is; } #endif #endif galib247/ga/garandom.C0100644003643600364360000002012610573535474013727 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- random.C mbwall 5sep95 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved DESCRIPTION: Random number stuff for use in GAlib. ---------------------------------------------------------------------------- */ #include #include #include #include static void bitseed(unsigned int seed=1); // If the machine has multiple processes, use the PID to help make the random // number generator seed more random. #if defined(GALIB_USE_PID) #include #define _GA_PID * getpid() #else #define _GA_PID #endif // Return a string indicating which random number generator was compiled-in to // the library. const char* GAGetRNG() { #if defined(GALIB_USE_RAN1) return "RAN1"; #elif defined(GALIB_USE_RAN2) return "RAN2"; #elif defined(GALIB_USE_RAN3) return "RAN3"; #elif defined(GALIB_USE_RAND) return "RAND"; #elif defined(GALIB_USE_RANDOM) return "RANDOM"; #elif defined(GALIB_USE_RAND48) return "RAND48"; #else return "UNKNOWN"; #endif } // Seed the random number generator with an appropriate value. We seed both // the random number generator and the random bit generator. Set the seed only // if a seed is not specified. If a seed is specified, then set the seed to // the specified value and use it. We remember the seed so that multiple calls // to this function with the same seed do not reset the generator. Subsequent // calls to this function with a different seed will initialize the generator // to the new seed. Multiple calls with a value of 0 do nothing (we do *not* // re-seed the generator because 0 is the default value and we don't want // people to re-seed the generator inadvertantly). // Some systems return a long as the return value for time, so we need to be // sure to get whatever variation from it that we can since our seed is only an // unsigned int. static unsigned int seed=0; unsigned int GAGetRandomSeed() { return seed; } void GARandomSeed(unsigned int s) { if(s == 0 && seed == 0) { unsigned long int tmp; while(seed == 0) { tmp = time(NULL) _GA_PID; for(unsigned int i=0; i= 1.0 || rsquare == 0.0); double val = -2.0 * log(rsquare) / rsquare; if(val > 0.0) factor = sqrt(val); else factor = 0.0; // should not happen, but might due to roundoff cachevalue = var1 * factor; cached = gaTrue; return (var2 * factor); } // This is the random bit generator Method II from numerical recipes in C. The // seed determines where in the cycle of numbers the generator will start, so // we don't need full 'long' precision in the argument to the seed function. #define IB1 1 #define IB2 2 #define IB5 16 #define IB18 131072L #define MASK (IB1+IB2+IB5) static unsigned long iseed; void bitseed(unsigned int seed) { iseed = seed; } int GARandomBit() { if (iseed & IB18) { iseed=((iseed ^ MASK) << 1) | IB1; return 1; } else { iseed <<= 1; return 0; } } #undef MASK #undef IB18 #undef IB5 #undef IB2 #undef IB1 // The following random number generators are from Numerical Recipes in C. // I have split them into a seed function and random number function. // The ran1 pseudo-random number generator. This one is OK to use as long as // you don't call it more than about 10^8 times, so for any long GA runs you'd // better use something with a longer period. #if defined(GALIB_USE_RAN1) #define IA 16807L #define IM 2147483647L #define AM (1.0/IM) #define IQ 127773L #define IR 2836L #define NTAB 32 #define NDIV (1+(IM-1)/NTAB) #define EPS 1.2e-7 #define RNMX (1.0-EPS) static long iy=0; static long iv[NTAB]; static long idum=0; void gasran1(unsigned int seed) { int j; long k; idum = seed; if (idum == 0) idum=1; if (idum < 0) idum = -idum; for (j=NTAB+7;j>=0;j--) { k=(idum)/IQ; idum=IA*(idum-k*IQ)-IR*k; if (idum < 0) idum += IM; if (j < NTAB) iv[j] = idum; } iy=iv[0]; } float garan1() { int j; long k; float temp; k=(idum)/IQ; idum=IA*(idum-k*IQ)-IR*k; if (idum < 0) idum += IM; j=iy/NDIV; iy=iv[j]; iv[j] = idum; if ((temp=AM*iy) > RNMX) return RNMX; else return temp; } #undef IA #undef IM #undef AM #undef IQ #undef IR #undef NTAB #undef NDIV #undef EPS #undef RNMX #endif // The ran2 pseudo-random number generator. It has a period of 2 * 10^18 and // returns a uniform random deviate on the interval (0.0, 1.0) excluding the // end values. idum initializes the sequence, so we create a separate seeding // function to set the seed. If you reset the seed then you re-initialize the // sequence. #if defined(GALIB_USE_RAN2) #define IM1 2147483563L #define IM2 2147483399L #define AM (1.0/IM1) #define IMM1 (IM1-1) #define IA1 40014L #define IA2 40692L #define IQ1 53668L #define IQ2 52774L #define IR1 12211L #define IR2 3791 #define NTAB 32 #define NDIV (1+IMM1/NTAB) #define EPS 1.2e-7 #define RNMX (1.0-EPS) static long idum2=123456789; static long iy=0; static long iv[NTAB]; static long idum=0; void gasran2(unsigned int seed) { int j; long k; idum = STA_CAST(long,seed); if (idum == 0) idum=1; if (idum < 0) idum = -idum; idum2=(idum); for (j=NTAB+7;j>=0;j--) { k=(idum)/IQ1; idum=IA1*(idum-k*IQ1)-k*IR1; if (idum < 0) idum += IM1; if (j < NTAB) iv[j] = idum; } iy=iv[0]; } float garan2() { int j; long k; float temp; k=(idum)/IQ1; idum=IA1*(idum-k*IQ1)-k*IR1; if (idum < 0) idum += IM1; k=idum2/IQ2; idum2=IA2*(idum2-k*IQ2)-k*IR2; if (idum2 < 0) idum2 += IM2; j=iy/NDIV; iy=iv[j]-idum2; iv[j] = idum; if (iy < 1) iy += IMM1; if ((temp=AM*iy) > RNMX) return RNMX; else return temp; } #undef IM1 #undef IM2 #undef AM #undef IMM1 #undef IA1 #undef IA2 #undef IQ1 #undef IQ2 #undef IR1 #undef IR2 #undef NTAB #undef NDIV #undef EPS #undef RNMX #endif #if defined(GALIB_USE_RAN3) // The ran3 pseudo-random number generator. It is *not* linear congruential. #define MBIG 1000000000 #define MSEED 161803398 #define MZ 0 #define FAC (1.0/MBIG) static int inext,inextp; static long ma[56]; void gasran3(unsigned int seed) { long idum = seed; long mj,mk; int i,ii,k; mj=labs(MSEED-labs(idum)); mj %= MBIG; ma[55]=mj; mk=1; for (i=1;i<=54;i++) { ii=(21*i) % 55; ma[ii]=mk; mk=mj-mk; if (mk < MZ) mk += MBIG; mj=ma[ii]; } for (k=1;k<=4;k++) for (i=1;i<=55;i++) { ma[i] -= ma[1+(i+30) % 55]; if (ma[i] < MZ) ma[i] += MBIG; } inext=0; inextp=31; } float garan3() { long mj; int i,ii,k; if (++inext == 56) inext=1; if (++inextp == 56) inextp=1; mj=ma[inext]-ma[inextp]; if (mj < MZ) mj += MBIG; ma[inext]=mj; return mj*FAC; } #undef MBIG #undef MSEED #undef MZ #undef FAC #endif galib247/ga/garandom.h0100644003643600364360000001424310573535473013776 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- random.h mbwall 29jun95 Copyright 1995 Massachusetts Institute of Technology DESCRIPTION: Initialize the random function by using the current time as the seed. We use the pid as well as the time for the random seed in an attempt to get rid of some of the periodicity from the low bits when using only the time as the random seed. These routines use the random/srandom routines to generate random numbers. The documentation says that rand/srand is about 30% faster than random/srandom, but rand/srand has a significantly smaller period so you'll get less random results. For the best results, use a RNG with a larger period (such as ran2). This is *not* implemented as a separate RNG class because I wanted to be able to inline everything as much as possible. Also, we don't need to switch RNGs for most purposes - I assume that compiling in the RNG is ok. In addition, many methods make use of RNG calls of a global nature - they should not contain a RNG, and they may not have access to a RNG other than the global functions. GARandomInt, GARandomFloat, GARandomDouble Return a number selected at random within the bounds low and high, inclusive. Don't forget the 'inclusive' part! If you're using this to get the index of an element in an array, be sure to use the last element of the array, not the number of elements in the array as the arguement for 'high'. If you screw up and pass a value for low that is less than the value for high, this routine does not complain. It will merrily return a possibly negative value. We need speed here, so there's no error checking. GARandomBit This is a faster implementation of GARandomInt(0,1). GAFlipCoin Simulate a coin toss. Use specified probability to bias toss. GAUnitGaussian Returns a number from a Gaussian distribution with mean 0 and stddev of 1 GAGaussianFloat, GAGaussianDouble Scaled versions of the gaussian distribution. You must specify a stddev, then these functions scale the distribution to that deviation. Mean is still 0 ---------------------------------------------------------------------------- */ #ifndef _ga_random_h_ #define _ga_random_h_ #include #include #include // Here we determine which random number generator will be used. The critical // parts here are the name of the random number generator (e.g. rand or random) // the name of the seed routine (e.g. srand or srandom), the maximum value of // the number returned by the generator (e.g. RAND_MAX or LONG_MAX), and the // C++ type of the number returned (e.g. int or long int). // If you want to use your own random function, this is where to declare it. // Just set the _GA_RND macros to the appropriate values for your random number // generator. // There are *many* ways to speed things up here if you know specifics about // the machine on which you're going to be running the code. For example, if // you have a floating coprocessor then you might want to use ran3 and convert // it so that it is entirely floating point (as described in NR in C). Or if // you're really daring, substitute some assembly code. For many bit-flipping // genetic algorithms the random number generator is the bottleneck, so this // isn't totally useless musing... #if defined(GALIB_USE_RAN1) || defined(GALIB_USE_RAN2) || defined(GALIB_USE_RAN3) #if defined(GALIB_USE_RAN1) #define _GA_RND garan1 #define _GA_RND_SEED gasran1 void gasran1(unsigned int seed=1); float garan1(); #elif defined(GALIB_USE_RAN2) #define _GA_RND garan2 #define _GA_RND_SEED gasran2 void gasran2(unsigned int seed=1); float garan2(); #elif defined(GALIB_USE_RAN3) #define _GA_RND garan3 #define _GA_RND_SEED gasran3 void gasran3(unsigned int seed=1); float garan3(); #endif inline int GARandomInt(){ return _GA_RND() > 0.5 ? 1 : 0; } inline int GARandomInt(int low, int high){ float val=STA_CAST(float,high)-STA_CAST(float,low)+(float)1; val*=_GA_RND(); return (STA_CAST(int,val)+low); } inline double GARandomDouble(){ return _GA_RND(); } inline double GARandomDouble(double low, double high){ double val=high-low; val*=_GA_RND(); return val+low; } inline float GARandomFloat(){ return _GA_RND(); } inline float GARandomFloat(float low, float high){ float val=high-low; val*=_GA_RND(); return val+low; } #elif defined(GALIB_USE_RAND) || defined(GALIB_USE_RANDOM) || defined(GALIB_USE_RAND48) #error It is usually a bad idea to use the system randum number generator! #error Be sure that your system generator works properly, then comment #error these lines to go ahead and do your compilation. #include #include #if defined(GALIB_USE_RANDOM) #define _GA_RND random #define _GA_RND_SEED srandom #define _GA_RND_MAX LONG_MAX #elif defined(GALIB_USE_RAND48) #define _GA_RND lrand48 #define _GA_RND_SEED srand48 #define _GA_RND_MAX LONG_MAX #else #define _GA_RND rand #define _GA_RND_SEED srand #define _GA_RND_MAX RAND_MAX #endif inline int GARandomInt(){ return _GA_RND() > _GA_RND_MAX/2 ? 1 : 0; } inline int GARandomInt(int low, int high){ return low + _GA_RND() % (high-low+1); } inline double GARandomDouble(){ double val=_GA_RND(); val/=_GA_RND_MAX; return val; } inline double GARandomDouble(double low, double high){ double val=high-low; val*=_GA_RND(); val/=_GA_RND_MAX; val+=low; return val; } inline float GARandomFloat(){ float val=_GA_RND(); val/=_GA_RND_MAX; return val; } inline float GARandomFloat(float low, float high){ float val=high-low; val*=_GA_RND(); val/=_GA_RND_MAX; val+=low; return val; } #endif unsigned int GAGetRandomSeed(); void GARandomSeed(unsigned int seed=0); void GAResetRNG(unsigned int seed); int GARandomBit(); double GAUnitGaussian(); inline GABoolean GAFlipCoin(float p){ return((p == 1.0) ? gaTrue : (p == 0.0) ? gaFalse : ((GARandomFloat() <= p) ? gaTrue : gaFalse)); } inline float GAGaussianFloat(float dev){ return (float)GAUnitGaussian()*dev; } inline double GAGaussianDouble(double dev){ return GAUnitGaussian() * dev; } const char* GAGetRNG(); #endif galib247/ga/GARealGenome.C0100644003643600364360000002354510573535474014375 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- real.C mbwall 11nov95 Copyright (c) 1995-1996 Massachusetts Institute of Technology all rights reserved DESCRIPTION: Source file for the real number specialization of the array genome. ---------------------------------------------------------------------------- */ #include // We must also specialize the allele set so that the alleles are handled // properly. Be sure to handle bounds correctly whether we are discretized // or continuous. Handle the case where someone sets stupid bounds that // might cause an infinite loop for exclusive bounds. template <> float GAAlleleSet::allele() const { float value = 0.0; if(core->type == GAAllele::ENUMERATED) value = core->a[GARandomInt(0, core->sz-1)]; else if(core->type == GAAllele::DISCRETIZED){ float n = (core->a[1] - core->a[0]) / core->a[2]; int m = (int)n; if(core->lowerb == GAAllele::EXCLUSIVE) m -= 1; if(core->upperb == GAAllele::EXCLUSIVE) m -= 1; value = core->a[0] + GARandomInt(0,(int)m) * core->a[2]; if(core->lowerb == GAAllele::EXCLUSIVE) value += core->a[2]; } else{ if(core->a[0] == core->a[1] && core->lowerb == GAAllele::EXCLUSIVE && core->upperb == GAAllele::EXCLUSIVE) { value = core->a[0]; } else { do { value = GARandomFloat(core->a[0], core->a[1]); } while ((core->lowerb == GAAllele::EXCLUSIVE && value == core->a[0]) || (core->upperb == GAAllele::EXCLUSIVE && value == core->a[1])); } } return value; } // If someone asks for a discretized item that is beyond the bounds, give them // one of the bounds. If they ask for allele item when there is no // discretization or enumeration, then error and return lower bound. template <> float GAAlleleSet::allele(unsigned int i) const { float value = 0.0; if(core->type == GAAllele::ENUMERATED) value = core->a[i % core->sz]; else if(core->type == GAAllele::DISCRETIZED){ float n = (core->a[1] - core->a[0])/core->a[2]; unsigned int m = (unsigned int)n; // what about bogus limits? if(core->lowerb == GAAllele::EXCLUSIVE) m -= 1; if(core->upperb == GAAllele::EXCLUSIVE) m -= 1; if(i > m) i = (int)m; value = core->a[0] + i*core->a[2]; if(core->lowerb == GAAllele::EXCLUSIVE) value += core->a[2]; } else{ GAErr(GA_LOC, "GAAlleleSet", "allele", gaErrNoAlleleIndex); value = core->a[0]; } return value; } // now the specialization of the genome itself. template <> const char * GA1DArrayAlleleGenome::className() const {return "GARealGenome";} template <> int GA1DArrayAlleleGenome::classID() const {return GAID::FloatGenome;} template <> GA1DArrayAlleleGenome:: GA1DArrayAlleleGenome(unsigned int length, const GAAlleleSet & s, GAGenome::Evaluator f, void * u) : GA1DArrayGenome(length, f, u){ naset = 1; aset = new GAAlleleSet[1]; aset[0] = s; initializer(DEFAULT_REAL_INITIALIZER); mutator(DEFAULT_REAL_MUTATOR); comparator(DEFAULT_REAL_COMPARATOR); crossover(DEFAULT_REAL_CROSSOVER); } template <> GA1DArrayAlleleGenome:: GA1DArrayAlleleGenome(const GAAlleleSetArray & sa, GAGenome::Evaluator f, void * u) : GA1DArrayGenome(sa.size(), f, u){ naset = sa.size(); aset = new GAAlleleSet[naset]; for(int i=0; i GA1DArrayAlleleGenome::~GA1DArrayAlleleGenome(){ delete [] aset; } #ifdef GALIB_USE_STREAMS // The read specialization takes in each number and stuffs it into the array. template <> int GA1DArrayAlleleGenome::read(STD_ISTREAM & is) { unsigned int i=0; float val; do{ is >> val; if(!is.fail()) gene(i++, val); } while(!is.fail() && !is.eof() && i < nx); if(is.eof() && i < nx){ GAErr(GA_LOC, className(), "read", gaErrUnexpectedEOF); is.clear(STD_IOS_BADBIT | is.rdstate()); return 1; } return 0; } // No need to specialize the write method. #endif /* ---------------------------------------------------------------------------- Operator specializations ---------------------------------------------------------------------------- */ // The Gaussian mutator picks a new value based on a Gaussian distribution // around the current value. We respect the bounds (if any). //*** need to figure out a way to make the stdev other than 1.0 int GARealGaussianMutator(GAGenome& g, float pmut){ GA1DArrayAlleleGenome &child= DYN_CAST(GA1DArrayAlleleGenome &, g); register int n, i; if(pmut <= 0.0) return(0); float nMut = pmut * (float)(child.length()); int length = child.length()-1; if(nMut < 1.0){ // we have to do a flip test on each element nMut = 0; for(i=length; i>=0; i--){ float value = child.gene(i); if(GAFlipCoin(pmut)){ if(child.alleleset(i).type() == GAAllele::ENUMERATED || child.alleleset(i).type() == GAAllele::DISCRETIZED) value = child.alleleset(i).allele(); else if(child.alleleset(i).type() == GAAllele::BOUNDED){ value += GAUnitGaussian(); value = GAMax(child.alleleset(i).lower(), value); value = GAMin(child.alleleset(i).upper(), value); } child.gene(i, value); nMut++; } } } else{ // only mutate the ones we need to for(n=0; n &mom= DYN_CAST(const GA1DArrayGenome &, p1); const GA1DArrayGenome &dad= DYN_CAST(const GA1DArrayGenome &, p2); int n=0; if(c1 && c2){ GA1DArrayGenome &sis=DYN_CAST(GA1DArrayGenome &, *c1); GA1DArrayGenome &bro=DYN_CAST(GA1DArrayGenome &, *c2); int len = GAMax(mom.length(), dad.length()); for(int i=0; i &sis = (c1 ? DYN_CAST(GA1DArrayGenome &, *c1) : DYN_CAST(GA1DArrayGenome &, *c2)); int len = GAMax(mom.length(), dad.length()); for(int i=0; i &mom= DYN_CAST(const GA1DArrayGenome &, p1); const GA1DArrayGenome &dad= DYN_CAST(const GA1DArrayGenome &, p2); int n=0; if(c1 && c2){ GA1DArrayGenome &sis=DYN_CAST(GA1DArrayGenome &, *c1); GA1DArrayGenome &bro=DYN_CAST(GA1DArrayGenome &, *c2); int len = GAMax(mom.length(), dad.length()); for(int i=0; i dad.gene(i)) dist = mom.gene(i) - dad.gene(i); else dist = dad.gene(i) - mom.gene(i); float lo = (GAMin(mom.gene(i), dad.gene(i))) - 0.5*dist; float hi = (GAMax(mom.gene(i), dad.gene(i))) + 0.5*dist; sis.gene(i, GARandomFloat(lo, hi)); bro.gene(i, GARandomFloat(lo, hi)); } n = 2; } else if(c1 || c2){ GA1DArrayGenome &sis = (c1 ? DYN_CAST(GA1DArrayGenome &, *c1) : DYN_CAST(GA1DArrayGenome &, *c2)); int len = GAMax(mom.length(), dad.length()); for(int i=0; i dad.gene(i)) dist = mom.gene(i) - dad.gene(i); else dist = dad.gene(i) - mom.gene(i); float lo = (GAMin(mom.gene(i), dad.gene(i))) - 0.5*dist; float hi = (GAMax(mom.gene(i), dad.gene(i))) + 0.5*dist; sis.gene(i, GARandomFloat(lo, hi)); } n = 1; } return n; } // force instantiations of this genome type. // // These must be included _after_ the specializations because some compilers // get all wigged out about the declaration/specialization order. Note that // some compilers require a syntax different than others when forcing the // instantiation (i.e. GNU wants the 'template class', borland does not). #ifndef GALIB_USE_AUTO_INST #include #include #if defined(__BORLANDC__) #define GALIB_REALGENOME_TEMPLATE_PREFACE #else #define GALIB_REALGENOME_TEMPLATE_PREFACE template class #endif GALIB_REALGENOME_TEMPLATE_PREFACE GAAlleleSet; GALIB_REALGENOME_TEMPLATE_PREFACE GAAlleleSetCore; GALIB_REALGENOME_TEMPLATE_PREFACE GAAlleleSetArray; GALIB_REALGENOME_TEMPLATE_PREFACE GAArray; GALIB_REALGENOME_TEMPLATE_PREFACE GA1DArrayGenome; GALIB_REALGENOME_TEMPLATE_PREFACE GA1DArrayAlleleGenome; #endif galib247/ga/GARealGenome.h0100644003643600364360000000536310573535474014440 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- real.h mbwall 25feb95 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved DESCRIPTION: This header defines the specialization of the array genome of type float for the real number genome. ---------------------------------------------------------------------------- */ #ifndef _ga_real_h_ #define _ga_real_h_ #include #include typedef GAAlleleSet GARealAlleleSet; typedef GAAlleleSetArray GARealAlleleSetArray; typedef GA1DArrayAlleleGenome GARealGenome; int GARealGaussianMutator(GAGenome &, float); // in one (and only one) place in the code that uses the string genome, you // should define INSTANTIATE_STRING_GENOME in order to force the specialization // for this genome. #if defined(INSTANTIATE_REAL_GENOME) #include #endif inline void GARealUniformInitializer(GAGenome& g){ GA1DArrayAlleleGenome::UniformInitializer(g); } inline void GARealOrderedInitializer(GAGenome& g){ GA1DArrayAlleleGenome::OrderedInitializer(g); } inline int GARealUniformMutator(GAGenome& g, float pmut){ return GA1DArrayAlleleGenome::FlipMutator(g, pmut); } inline int GARealSwapMutator(GAGenome& g, float pmut){ return GA1DArrayGenome::SwapMutator(g, pmut); } inline int GARealUniformCrossover(const GAGenome& a, const GAGenome& b, GAGenome* c, GAGenome* d) { return GA1DArrayGenome::UniformCrossover(a,b,c,d); } inline int GARealEvenOddCrossover(const GAGenome& a, const GAGenome& b, GAGenome* c, GAGenome* d) { return GA1DArrayGenome::EvenOddCrossover(a,b,c,d); } inline int GARealOnePointCrossover(const GAGenome& a, const GAGenome& b, GAGenome* c, GAGenome* d) { return GA1DArrayGenome::OnePointCrossover(a,b,c,d); } inline int GARealTwoPointCrossover(const GAGenome& a, const GAGenome& b, GAGenome* c, GAGenome* d) { return GA1DArrayGenome::TwoPointCrossover(a,b,c,d); } inline int GARealPartialMatchCrossover(const GAGenome& a, const GAGenome& b, GAGenome* c, GAGenome* d) { return GA1DArrayGenome::PartialMatchCrossover(a,b,c,d); } inline int GARealOrderCrossover(const GAGenome& a, const GAGenome& b, GAGenome* c, GAGenome* d) { return GA1DArrayGenome::OrderCrossover(a,b,c,d); } inline int GARealCycleCrossover(const GAGenome& a, const GAGenome& b, GAGenome* c, GAGenome* d) { return GA1DArrayGenome::CycleCrossover(a,b,c,d); } int GARealArithmeticCrossover(const GAGenome& a, const GAGenome& b, GAGenome* c, GAGenome* d); int GARealBlendCrossover(const GAGenome& a, const GAGenome& b, GAGenome* c, GAGenome* d); #endif galib247/ga/GAScaling.C0100644003643600364360000002264210573535473013733 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- scaling.C mbwall 10aug94 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved DESCRIPTION: Class definitions for the scaling objects. These objects translate (scale) the raw objective scores of a population into 'fitness' scores that are used to determine which genomes are fit for mating/selection. In all of these routines we do a check to be sure that we have enough space to do our evaluations. We don't need to do this so long as the population objects that call us do the test themselves. I'll leave the redundancy for now. ---------------------------------------------------------------------------- */ #include #include #include #include #include #include float gaDefLinearScalingMultiplier = 1.2; float gaDefSigmaTruncationMultiplier = 2.0; float gaDefPowerScalingFactor = 1.0005; float gaDefSharingCutoff = 1.0; /* ---------------------------------------------------------------------------- NoScaling ---------------------------------------------------------------------------- */ // Assign the fitness scores to be the same as the objective scores for all of // the individuals in the population. void GANoScaling::evaluate(const GAPopulation& p) { for(int i=0; i ((double)c * pave - pmax)/((double)c - 1.0)){ delta = pmax - pave; a = ((double)c - 1.0) * pave / delta; b = pave * (pmax - (double)c * pave) / delta; } else{ // stretch to make min be 0 delta = pave - pmin; a = pave / delta; b = -pmin * pave / delta; } // and now we calculate the scaled scaled values. Negative scores are not // allowed with this kind of scaling, so check for negative values. If we get // a negative value, dump an error message then set all of the scores to 0. for(int i=0; i (int)N){ delete [] d; N = p.size(); d = new float[N*N]; } int n = p.size(); int i, j; if(df) { for(i=0; iminimaxi(); else mm = ((p.order() == GAPopulation::HIGH_IS_BEST) ? GAGeneticAlgorithm::MAXIMIZE : GAGeneticAlgorithm::MINIMIZE); } else { mm = _minmax; } for(i=0; i= _sigma) ? 0.0 : 1.0 - d[i*n+j]/_sigma); else sum += ((d[i*n+j]>=_sigma) ? 0.0 : 1.0-pow(d[i*n+j]/_sigma,_alpha)); } } double f; if(mm == GAGeneticAlgorithm::MINIMIZE) f = p.individual(i).score() * sum; else f = p.individual(i).score() / sum; p.individual(i).fitness((float)f); // might lose information here! } } void GASharing::copy(const GAScalingScheme & arg){ if(&arg == this) return; GAScalingScheme::copy(arg); const GASharing& s = DYN_CAST(const GASharing&, arg); delete [] d; _minmax = s._minmax; _sigma = s._sigma; _alpha = s._alpha; df = s.df; N = s.N; d = new float[N*N]; memcpy(d, s.d, N*N*sizeof(float)); } // The cutoff for triangular sharing must always be greater than 0 float GASharing::sigma(float c) { if(c <= 0.0){ GAErr(GA_LOC, className(), "sigma", gaErrBadSharingCutoff); return _sigma; } return _sigma = c; } int GASharing::minimaxi(int i) { if(i == GAGeneticAlgorithm::MAXIMIZE) _minmax = GAGeneticAlgorithm::MAXIMIZE; else if(i == GAGeneticAlgorithm::MINIMIZE) _minmax = GAGeneticAlgorithm::MINIMIZE; else _minmax = 0; return _minmax; } #endif galib247/ga/GAScaling.h0100644003643600364360000002512610573535474014001 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- scaling.h mbwall 10aug94 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved DESCRIPTION: This is the GAScaling class. It is used to do scaling on a population. When a genome is evaluated, the user's objective function provides an overall rating for each genome. The GA is concerned with fitness, not objective score (unless you do no scaling). So this object is the container for the scaled values. Examples of scaling include linear scaling, sigma truncation, and power law. Goldberg's sharing function is also a type of scaling, and it is implemented here as a unique class. The scaling class is designed to be used with a population. It is stupid - it does know how to update itself, but it must be told when. ---------------------------------------------------------------------------- */ #ifndef _ga_scaling_h_ #define _ga_scaling_h_ #include #include #include #include class GAPopulation; extern float gaDefLinearScalingMultiplier; extern float gaDefSigmaTruncationMultiplier; extern float gaDefPowerScalingFactor; extern float gaDefSharingCutoff; /* ---------------------------------------------------------------------------- Scaling The scaling object is used to scale the objective scores of a population to avoid clustering and premature convergence (among other things). See golberg for more about the theory. This is basically just a container for any data that the scaling object might need to do its thing. The simplest scalings don't store any data. ---------------------------------------------------------------------------- */ class GAScalingScheme : public GAID { public: GADefineIdentity("GAScalingScheme", GAID::Scaling); GAScalingScheme() {} GAScalingScheme(const GAScalingScheme& s) { copy(s); } GAScalingScheme& operator=(const GAScalingScheme& s) {copy(s); return *this;} virtual ~GAScalingScheme() { } virtual GAScalingScheme * clone() const=0; virtual void copy(const GAScalingScheme &) {} virtual void evaluate(const GAPopulation & p)=0; }; /* ---------------------------------------------------------------------------- NoScaling ---------------------------------------------------------------------------- */ class GANoScaling : public GAScalingScheme { public: GADefineIdentity("GANoScaling", GAID::NoScaling); GANoScaling() : GAScalingScheme() {} GANoScaling(const GANoScaling &) : GAScalingScheme() {} GANoScaling& operator=(const GAScalingScheme&){ return *this; } virtual ~GANoScaling(){} virtual GAScalingScheme * clone() const {return new GANoScaling(*this);} virtual void evaluate(const GAPopulation & p); }; /* ---------------------------------------------------------------------------- LinearScaling This scaling object does linear scaling as described in goldberg pp 122-124. ---------------------------------------------------------------------------- */ #if USE_LINEAR_SCALING == 1 class GALinearScaling : public GAScalingScheme { public: GADefineIdentity("GALinearScaling", GAID::LinearScaling); GALinearScaling(float fm=gaDefLinearScalingMultiplier) {multiplier(fm);} GALinearScaling(const GALinearScaling & arg) {copy(arg);} GALinearScaling & operator=(const GAScalingScheme & arg) {copy(arg); return(*this);} virtual ~GALinearScaling(){} virtual GAScalingScheme * clone() const {return new GALinearScaling(*this);} virtual void evaluate(const GAPopulation & p); virtual void copy(const GAScalingScheme & arg){ if(&arg != this){ GAScalingScheme::copy(arg); c=(DYN_CAST(const GALinearScaling&,arg)).c; } } float multiplier(float fm); float multiplier() const {return c;} protected: float c; // linear scaling multiplier }; #endif /* ---------------------------------------------------------------------------- SigmaTruncationScaling This scaling object does sigma truncation as defined in goldberg p124. ---------------------------------------------------------------------------- */ #if USE_SIGMA_TRUNC_SCALING == 1 class GASigmaTruncationScaling : public GAScalingScheme { public: GADefineIdentity("GASigmaTruncationScaling", GAID::SigmaTruncationScaling); GASigmaTruncationScaling(float m=gaDefSigmaTruncationMultiplier) {multiplier(m);} GASigmaTruncationScaling(const GASigmaTruncationScaling & arg){copy(arg);} GASigmaTruncationScaling & operator=(const GAScalingScheme & arg) {copy(arg); return(*this);} virtual ~GASigmaTruncationScaling(){} virtual GAScalingScheme * clone() const {return new GASigmaTruncationScaling(*this);} virtual void evaluate(const GAPopulation & p); virtual void copy(const GAScalingScheme & arg){ if(&arg != this){ GAScalingScheme::copy(arg); c=(DYN_CAST(const GASigmaTruncationScaling&,arg)).c; } } float multiplier(float fm); float multiplier() const {return c;} protected: float c; // std deviation multiplier }; #endif /* ---------------------------------------------------------------------------- PowerLawScaling This scaling object does power law scaling as defined in goldberg p124. ---------------------------------------------------------------------------- */ #if USE_POWER_LAW_SCALING == 1 class GAPowerLawScaling : public GAScalingScheme { public: GADefineIdentity("GAPowerLawScaling", GAID::PowerLawScaling); GAPowerLawScaling(float f=gaDefPowerScalingFactor) {k = f;} GAPowerLawScaling(const GAPowerLawScaling & arg) {copy(arg);} GAPowerLawScaling & operator=(const GAScalingScheme & arg) {copy(arg); return(*this);} virtual ~GAPowerLawScaling(){} virtual GAScalingScheme * clone() const {return new GAPowerLawScaling(*this);} virtual void evaluate(const GAPopulation & p); virtual void copy(const GAScalingScheme & arg){ if(&arg != this){ GAScalingScheme::copy(arg); k=(DYN_CAST(const GAPowerLawScaling&,arg)).k; } } float power(float p){return k=p;} float power() const {return k;} protected: float k; // power scaling factor }; #endif /* ---------------------------------------------------------------------------- Sharing This scaling object does sharing as described in goldberg p 192. This implementation does triangular sharing with the (optional) alpha parameter for changing the curvature of the sharing range and the (required) sigma parameter for controlling the range of influence. If you want a different type of sharing function, then derive from this class and define a new (virtual) evaluate method and add whatever member data you need to specify the shape of your sharing function. We use the distance function to scale the objective scores of the genomes so that if there are many similar genomes in a population their scores will be decreased, thus giving sub-species a greater chance to reproduce. This sharing function is defined as follows: / | 1 - (d(i,j)/sigma) ^ alpha d(i,j) < sigma s(d(i,j)) = | | 0 d(i,j) >= sigma \ where d is the distance between any two individuals and is defined such that d(i,j) = 0 means that individuals i and j are identical. d() has no upper bound, but it is never negative. The alpha controls the shape of the sharing function. When alpha=1 then the 'curve' is a straight line. If alpha is < 1 then the curves are concave, if alpha is > 1 then the curves are convex. If you decide to use this type of sharing, be careful of the sigma value that you use. It can make a HUGE difference, depending upon the objective. Distance functions are independent of the sharing functions (as defined in Goldberg, that is). A similarity (distance) function is used with the sharing object. It is a type of speciation (similar in functionality to DeJong crowding, but this uses fitness scaling rather than replacement strategy to affect the speciation). If the genomes are identical, the similarity function should return a value of 0.0, if completely different then return a value of 1.0. 0 means less diversity means all genomes are the same. You can specify whether the scaling should be maximize or minimize based. If you are maximizing, the scaling will divide the raw score by the scaling factor. If you are minimizing, the scaling will multiply the score by the scaling factor. (By definition, the scaling factor will always be >= 1.0) By default, the scaling object uses the max/min settings that it contains (so you can set the scaling independently of the GA). If the scaling's min/max was not set, then it tries to use the min/max settings in the GA that owns the population to which the scaling object is attached. If there is no GA, then it bases its min/max on the sort order of the population. You can set the minimaxi to: GA::MINIMIZE - scale by multiplying the raw scores GA::MAXIMIZE - scale by dividing the raw scores 0 - minimize or maximize based upon the GA's settings *** This should be called TriangularSharing rather than simply Sharing. ---------------------------------------------------------------------------- */ #if USE_SHARING == 1 class GASharing : public GAScalingScheme { public: GADefineIdentity("GASharing", GAID::Sharing); GASharing(GAGenome::Comparator func, float cut=gaDefSharingCutoff, float a=1.0) { N=0; d=(float*)0; df=func; _sigma = cut; _alpha = a; _minmax = 0; } GASharing(float cut=gaDefSharingCutoff, float a=1.0) { N=0; d=(float*)0; df=0; _sigma = cut; _alpha = a; _minmax = 0; } GASharing(const GASharing & arg) { N=0; d=(float*)0; copy(arg); } GASharing & operator=(const GAScalingScheme & arg){copy(arg); return(*this);} virtual ~GASharing(){ delete [] d;} virtual GAScalingScheme * clone() const {return new GASharing(*this);} virtual void copy(const GAScalingScheme & arg); virtual void evaluate(const GAPopulation & p); GAGenome::Comparator distanceFunction(GAGenome::Comparator f){return df=f;} GAGenome::Comparator distanceFunction() const {return df;} float sigma(float); float sigma() const { return _sigma; } float alpha(float c) { return _alpha = c; } float alpha() const { return _alpha; } int minimaxi(int i); int minimaxi() const { return _minmax; } protected: GAGenome::Comparator df; // the user-defined distance function unsigned int N; // how many do we have? (n of n-by-n) float *d; // the distances for each genome pair float _sigma; // absolute cutoff from central point float _alpha; // controls the curvature of sharing f int _minmax; // should we minimize or maximize? }; #endif #endif galib247/ga/GASelector.C0100644003643600364360000003671710573535474014144 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- selector.C mbwall 10aug94 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved DESCRIPTION: This file defines the built-in selection objects for GAlib. ---------------------------------------------------------------------------- */ #include #include #include #include #include #include #if USE_DS_SELECTOR == 1 static void GAQuickSort(unsigned int *, float *, int, int); #endif /* ---------------------------------------------------------------------------- RankSelector ---------------------------------------------------------------------------- */ // Any population may contain more than one individual with the same score. // This method must be able to return any one of those 'best' individuals, so // we do a short search here to find out how many of those 'best' there are. // This routine assumes that the 'best' individual is that with index 0. It // uses either the fitness or objective score to do the ranking, depending on // which was selected in the selector object. #if USE_RANK_SELECTOR == 1 GAGenome & GARankSelector::select() const { int i, count=1; GAPopulation::SortBasis basis = (which == SCALED ? GAPopulation::SCALED : GAPopulation::RAW); pop->sort(gaFalse, basis); if(which == SCALED){ for(i=1; isize() && pop->best(i,basis).fitness() == pop->best(0,basis).fitness(); i++) count++; } else{ for(i=1; isize() && pop->best(i,basis).score() == pop->best(0,basis).score(); i++) count++; } return pop->best(GARandomInt(0,count-1),basis); } #endif /* ---------------------------------------------------------------------------- UniformSelector ---------------------------------------------------------------------------- */ // Randomly select an individual from the population. This selector does not // care whether it operates on the fitness or objective scores. #if USE_UNIFORM_SELECTOR == 1 GAGenome& GAUniformSelector::select() const { return pop->individual(GARandomInt(0, pop->size()-1)); } #endif /* ---------------------------------------------------------------------------- RouletteWheelSelector ---------------------------------------------------------------------------- */ // This selection routine is straight out of Goldberg's Genetic Algorithms // book (with the added restriction of not allowing zero scores - Goldberg // does not address this degenerate case). We look through the members of the // population using a weighted roulette wheel. Likliehood of selection is // proportionate to the fitness score. // This is a binary search method (using cached partial sums). It assumes // that the genomes are in order from best (0th) to worst (n-1). #if USE_ROULETTE_SELECTOR == 1 || USE_TOURNAMENT_SELECTOR == 1 GAGenome & GARouletteWheelSelector::select() const { float cutoff; int i, upper, lower; cutoff = GARandomFloat(); lower = 0; upper = pop->size()-1; while(upper >= lower){ i = lower + (upper-lower)/2; assert(i >= 0 && i < n); if(psum[i] > cutoff) upper = i-1; else lower = i+1; } lower = GAMin(pop->size()-1, lower); lower = GAMax(0, lower); return pop->individual(lower, (which == SCALED ? GAPopulation::SCALED : GAPopulation::RAW)); } // Update our list of partial sums. Use the appropriate fitness/objective // scores as determined by the flag. The delete/alloc assumes that the pop // size won't be changing a great deal. // Our selector requires that the population is sorted (it uses a binary // search to go faster) so we force the sort here. void GARouletteWheelSelector::update() { if(pop->size() != n){ delete [] psum; n = pop->size(); psum = new float [n]; } int i; if(which == GASelectionScheme::RAW){ if(pop->max() == pop->min()){ for(i=0; imax() > 0 && pop->min() >= 0) || (pop->max() <= 0 && pop->min() < 0)){ pop->sort(gaFalse, GAPopulation::RAW); if(pop->order() == GAPopulation::HIGH_IS_BEST){ psum[0] = pop->individual(0, GAPopulation::RAW).score(); for(i=1; iindividual(i, GAPopulation::RAW).score() + psum[i-1]; for(i=0; iindividual(0, GAPopulation::RAW).score() + pop->max() + pop->min(); for(i=1; iindividual(i, GAPopulation::RAW).score() + pop->max() + pop->min() + psum[i-1]; for(i=0; ifitmax() == pop->fitmin()){ for(i=0; ifitmax() > 0 && pop->fitmin() >= 0) || (pop->fitmax() <= 0 && pop->fitmin() < 0)){ pop->sort(gaFalse, GAPopulation::SCALED); if(pop->order() == GAPopulation::HIGH_IS_BEST){ psum[0] = pop->individual(0, GAPopulation::SCALED).fitness(); for(i=1; iindividual(i, GAPopulation::SCALED).fitness() + psum[i-1]; for(i=0; iindividual(0, GAPopulation::SCALED).fitness() + pop->fitmax() + pop->fitmin(); for(i=1; iindividual(i, GAPopulation::SCALED).fitness() + pop->fitmax() + pop->fitmin() + psum[i-1]; for(i=0; isize()-1; while(upper >= lower){ i = lower + (upper-lower)/2; assert(i >= 0 && i < n); if(psum[i] > cutoff) upper = i-1; else lower = i+1; } lower = GAMin(pop->size()-1, lower); lower = GAMax(0, lower); picked = lower; cutoff = GARandomFloat(); lower = 0; upper = pop->size()-1; while(upper >= lower){ i = lower + (upper-lower)/2; assert(i >= 0 && i < n); if(psum[i] > cutoff) upper = i-1; else lower = i+1; } lower = GAMin(pop->size()-1, lower); lower = GAMax(0, lower); GAPopulation::SortBasis basis = (which == SCALED ? GAPopulation::SCALED : GAPopulation::RAW); if(pop->order() == GAPopulation::LOW_IS_BEST){ if(pop->individual(lower,basis).score() < pop->individual(picked,basis).score()) picked = lower; } else{ if(pop->individual(lower,basis).score() > pop->individual(picked,basis).score()) picked = lower; } return pop->individual(picked,basis); } #endif /* ---------------------------------------------------------------------------- SRSSelector - stochastic remainder sampling The selection happens in two stages. First we generate an array using the integer and remainder parts of the expected number of individuals. Then we pick an individual from the population by randomly picking from this array. This is implemented just as in Goldberg's book. Not very efficient... In Goldberg's implementation he uses a variable called 'nremain' so that multiple calls to the selection routine can be dependent upon previous calls. We don't have that option with this architecture; we would need to make selection an object coupled closely with the population to make that work. ---------------------------------------------------------------------------- */ #if USE_SRS_SELECTOR == 1 GAGenome & GASRSSelector::select() const { return pop->individual(choices[GARandomInt(0, pop->size()-1)], (which == SCALED ? GAPopulation::SCALED : GAPopulation::RAW)); } // Make sure we have enough memory to work with. Set values of choices array // to appropriate values. // This is the preselection part. Figure out how many we should expect of // each individual. An individual with e of 4.3 will get 4 places and have a // 30% chance of a 5th place. // This implementation only works if fitness scores are strictly positive or // strictly negative. void GASRSSelector::update() { if(n != (unsigned int)(pop->size())){ delete [] fraction; delete [] choices; n = pop->size(); fraction = new float [n]; choices = new unsigned int [n]; } int i,ne,k=0; if(which == GASelectionScheme::RAW){ if(pop->ave() == 0 || pop->max() == pop->min()){ for(i=0; (unsigned int)imax() >= 0 && pop->min() >= 0) || (pop->max() <= 0 && pop->min() <= 0)){ float expected; for(i=0; isize(); i++){ if(pop->order() == GAPopulation::HIGH_IS_BEST) expected = pop->individual(i, GAPopulation::RAW).score()/pop->ave(); else expected = (-pop->individual(i, GAPopulation::RAW).score() + pop->max() + pop->min())/pop->ave(); ne = (int)expected; fraction[i] = expected - ne; while(ne > 0 && k < (int)n){ assert(k >= 0 && k < (int)n); choices[k] = i; k++; ne--; } } i=0; while(k < pop->size()){ if(fraction[i] > 0.0 && GAFlipCoin(fraction[i])){ assert(k >= 0 && k < (int)n); assert(i >= 0 && i < (int)n); choices[k] = i; fraction[i] -= 1.0; k++; } i++; if(i >= pop->size()) i=0; } } else { GAErr(GA_LOC, className(), "update", "objective scores are not strictly negative or strictly positive", "this selection method cannot be used with these scores"); } } else { if(pop->fitave() == 0 || pop->fitmax() == pop->fitmin()){ for(i=0; (unsigned int)ifitmax() >= 0 && pop->fitmin() >= 0) || (pop->fitmax() <= 0 && pop->fitmin() <= 0)){ float expected; for(i=0; isize(); i++){ if(pop->order() == GAPopulation::HIGH_IS_BEST) expected = pop->individual(i, GAPopulation::SCALED).fitness()/pop->fitave(); else expected = (-pop->individual(i, GAPopulation::SCALED).fitness() + pop->fitmax() + pop->fitmin()) / pop->fitave(); ne = (int)expected; fraction[i] = expected - ne; while(ne > 0 && k < (int)n){ assert(k >= 0 && k < (int)n); choices[k] = i; k++; ne--; } } i=0; int flag = 1; while(k < pop->size() && flag){ if(i >= pop->size()){ i=0; flag = 0; } if(fraction[i] > 0.0 && GAFlipCoin(fraction[i])){ assert(k >= 0 && k < (int)n); assert(i >= 0 && i < (int)n); choices[k] = i; fraction[i] -= 1.0; k++; flag = 1; } i++; } if(k < pop->size()){ for(; ksize(); k++) choices[k] = GARandomInt(0,pop->size()-1); } } else { GAErr(GA_LOC, className(), "update", "fitness scores are not strictly negative or strictly positive", "this selection method cannot be used with these scores"); } } } #endif /* ---------------------------------------------------------------------------- DSSelector - deterministic sampling This is implemented as described in Goldberg's book. ---------------------------------------------------------------------------- */ #if USE_DS_SELECTOR == 1 GAGenome & GADSSelector::select() const { return pop->individual(choices[GARandomInt(0, pop->size()-1)], (which == SCALED ? GAPopulation::SCALED : GAPopulation::RAW)); } // Make sure we have enough memory to work with. Then calc the choices array. // This is the preselection part. Figure out how many we should expect of // each individual. An individual with e of 4.3 will get 4 places, an // individual with e of 5.9 will get 5 places. If there are any spaces // remaining then we fill them with the individuals with highest fractional // values (don't as *ME* why Goldberg does it this way...) // This implementation only works if fitness scores are strictly positive or // strictly negative. void GADSSelector::update() { if(n != (unsigned int)pop->size()){ delete [] fraction; delete [] choices; delete [] idx; n = pop->size(); fraction = new float [n]; choices = new unsigned int [n]; idx = new unsigned int [n]; } int i,ne,k=0; if(which == GASelectionScheme::RAW){ if(pop->ave() == 0 || pop->max() == pop->min()){ for(i=0; (unsigned int)imax() >= 0 && pop->min() >= 0) || (pop->max() <= 0 && pop->min() <= 0)){ float expected; for(i=0; isize(); i++){ idx[i] = i; if(pop->order() == GAPopulation::HIGH_IS_BEST) expected = pop->individual(i, GAPopulation::RAW).score()/pop->ave(); else expected = (-pop->individual(i, GAPopulation::RAW).score() + pop->max() + pop->min())/pop->ave(); ne = (int)expected; fraction[i] = expected - ne; while(ne > 0 && k < (int)n){ assert(k >= 0 && k < (int)n); choices[k] = i; k++; ne--; } } GAQuickSort(idx, fraction, 0, n-1); for(i=pop->size()-1; ksize(); k++, i--) choices[k] = idx[i]; } else{ GAErr(GA_LOC, className(), "update", "objective scores are not strictly negative or strictly positive", "this selection method cannot be used with these scores"); } } else{ if(pop->fitave() == 0 || pop->fitmax() == pop->fitmin()){ for(i=0; (unsigned int)ifitmax() >= 0 && pop->fitmin() >= 0) || (pop->fitmax() <= 0 && pop->fitmin() <= 0)){ float expected; for(i=0; isize(); i++){ idx[i] = i; if(pop->order() == GAPopulation::HIGH_IS_BEST) expected = pop->individual(i, GAPopulation::SCALED).fitness()/pop->fitave(); else expected = (-pop->individual(i, GAPopulation::SCALED).fitness() + pop->fitmax() + pop->fitmin()) / pop->fitave(); ne = (int)expected; fraction[i] = expected - ne; while(ne > 0 && k < (int)n){ assert(k >= 0 && k < (int)n); choices[k] = i; k++; ne--; } } GAQuickSort(idx, fraction, 0, n-1); for(i=pop->size()-1; ksize(); k++, i--) choices[k] = idx[i]; } else{ GAErr(GA_LOC, className(), "update", "fitness scores are not strictly negative or strictly positive", "this selection method cannot be used with these scores"); } } } static void GAQuickSort(unsigned int *c, float *s, int l, int r) { int i,j; float v; unsigned int tc; float ts; if(r > l){ v = s[r]; i = l-1; j = r; for(;;){ while(s[++i] < v); // might exceed max array limit here while(s[--j] > v && j > 0); if(i >= j) break; tc = c[i]; c[i] = c[j]; c[j] = tc; ts = s[i]; s[i] = s[j]; s[j] = ts; } tc = c[i]; c[i] = c[r]; c[r] = tc; ts = s[i]; s[i] = s[r]; s[r] = ts; GAQuickSort(c,s,l,i-1); GAQuickSort(c,s,i+1,r); } } #endif galib247/ga/GASelector.h0100644003643600364360000002462210573535473014200 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- selector.h mbwall 10aug94 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved DESCRIPTION: The selectors are functions that use information in fitness objects to pick genomes from a population. There are a number of selection criteria, and not every selection method will work with every fitness object. These are the pre-defined selection methods. A brief outline of what each one does is given here, but for more details (especially the theoretical foundations for each method), see Goldberg. See the source file for some implementation details that Goldberg does not delve into. The selection methods can, to some extent, be mixed and matched with the various scaling methods. If you want to do speciating selection (e.g. DeJong-style crowding with Hamming distance) then you will have to write your own selection method. Rank - pick the genome with the best fitness (not objective score) RouletteWheel - weighted selection where individuals with better fitness have a greater chance of being selected than those with lower scores. Tournament - similar to roulette, but instead of choosing one, choose two then pick the better of the two as the selected individuals Uniform - stochastic uniform selection picks randomly from the population. Each individual has as much chance as any other. SRS - stochastic remainder selection does a preselection based on the expected number of each genome, then a random sampling on the preselected list. DS - deterministic sampling is implemented as described in Goldberg's book (as much as I could understand it, anyway). ---------------------------------------------------------------------------- */ #ifndef _ga_selector_h_ #define _ga_selector_h_ #include #include class GAGenome; class GAPopulation; /* ---------------------------------------------------------------------------- The base class definition for the selector object defines the interface. Any derived selector must define a clone member and a select member. If you add any special data members then you should also define a copy member. Any selector can do its business based on fitness or objective scores. The base selector provides the mechanism for this. Derived classes can use it if they want to, or ignore it. ---------------------------------------------------------------------------- */ class GASelectionScheme : public GAID { public: GADefineIdentity("GASelectionScheme", GAID::Selection); enum { RAW, SCALED }; GASelectionScheme(int w=SCALED) { which = w;} GASelectionScheme(const GASelectionScheme& orig) { copy(orig); } GASelectionScheme& operator=(const GASelectionScheme& orig) { if(&orig != this) copy(orig); return *this; } virtual ~GASelectionScheme() {} virtual GASelectionScheme* clone() const=0; virtual void copy(const GASelectionScheme& orig) { pop=orig.pop; which=orig.which; } virtual void assign(GAPopulation& p) { pop = &p; } virtual void update() {} virtual GAGenome& select() const=0; protected: GAPopulation* pop; int which; // should we use fitness or objective scores? }; /* ---------------------------------------------------------------------------- The rank selector simply picks the best individual in the population. You can specify whether the selector should use the raw (objective) scores or the scaled (fitness) scores to determine the best individual. Default is fitness. ---------------------------------------------------------------------------- */ #if USE_RANK_SELECTOR == 1 class GARankSelector : public GASelectionScheme { public: GADefineIdentity("GARankSelector", GAID::RankSelection); GARankSelector(int w=GASelectionScheme::SCALED) : GASelectionScheme(w) {} GARankSelector(const GARankSelector& orig) { copy(orig); } GARankSelector& operator=(const GASelectionScheme& orig) { if(&orig != this) copy(orig); return *this; } virtual ~GARankSelector() {} virtual GASelectionScheme* clone() const { return new GARankSelector; } virtual GAGenome& select() const; }; #endif /* ---------------------------------------------------------------------------- Roulette wheel uses a fitness-proportional algorithm for selecting individuals. ---------------------------------------------------------------------------- */ #if USE_ROULETTE_SELECTOR == 1 || USE_TOURNAMENT_SELECTOR == 1 class GARouletteWheelSelector : public GASelectionScheme { public: GADefineIdentity("GARouletteWheelSelector", GAID::RouletteWheelSelection); GARouletteWheelSelector(int w=GASelectionScheme::SCALED) : GASelectionScheme(w) { psum = (float*)0; n = 0; } GARouletteWheelSelector(const GARouletteWheelSelector& orig) { psum = (float*)0; n = 0; copy(orig); } GARouletteWheelSelector& operator=(const GASelectionScheme& orig) { if(&orig != this) copy(orig); return *this; } virtual ~GARouletteWheelSelector() { delete [] psum; } virtual GASelectionScheme* clone() const { return new GARouletteWheelSelector; } virtual void copy(const GASelectionScheme& orig) { GASelectionScheme::copy(orig); const GARouletteWheelSelector& sel = DYN_CAST(const GARouletteWheelSelector&,orig); delete [] psum; n = sel.n; psum = new float[n]; memcpy(psum, sel.psum, n * sizeof(float)); } virtual GAGenome& select() const; virtual void update(); protected: int n; float* psum; }; #endif /* ---------------------------------------------------------------------------- This version of the tournament selector does two roulette wheel selections then picks the better of the two. We derive from the roulette wheel class so that we can use its update method. ---------------------------------------------------------------------------- */ #if USE_TOURNAMENT_SELECTOR == 1 class GATournamentSelector : public GARouletteWheelSelector { public: GADefineIdentity("GATournamentSelector", GAID::TournamentSelection); GATournamentSelector(int w=GASelectionScheme::SCALED) : GARouletteWheelSelector(w) {} GATournamentSelector(const GATournamentSelector& orig) { copy(orig); } GATournamentSelector& operator=(const GASelectionScheme& orig) { if(&orig != this) copy(orig); return *this; } virtual ~GATournamentSelector() {} virtual GASelectionScheme* clone() const { return new GATournamentSelector; } virtual GAGenome& select() const; }; #endif /* ---------------------------------------------------------------------------- Stochastic uniform sampling selection. This is just a fancy name for random sampling. Any individual in the population has as much chance of being selected as any other. ---------------------------------------------------------------------------- */ #if USE_UNIFORM_SELECTOR == 1 class GAUniformSelector : public GASelectionScheme { public: GADefineIdentity("GAUniformSelector", GAID::UniformSelection); GAUniformSelector(int w=GASelectionScheme::SCALED) : GASelectionScheme(w) { } GAUniformSelector(const GAUniformSelector& orig) { copy(orig); } GAUniformSelector& operator=(const GASelectionScheme& orig) { if(&orig != this) copy(orig); return *this; } virtual ~GAUniformSelector() { } virtual GASelectionScheme* clone() const { return new GAUniformSelector; } virtual GAGenome& select() const; }; #endif /* ---------------------------------------------------------------------------- Stochastic remainder sampling selection. ---------------------------------------------------------------------------- */ #if USE_SRS_SELECTOR == 1 class GASRSSelector : public GASelectionScheme { public: GADefineIdentity("GASRSSelector", GAID::SRSSelection); GASRSSelector(int w=GASelectionScheme::SCALED) : GASelectionScheme(w) { fraction = (float*)0; choices = (unsigned int *)0; n = 0; } GASRSSelector(const GASRSSelector& orig) { fraction = (float*)0; choices = (unsigned int *)0; n = 0; copy(orig); } GASRSSelector& operator=(const GASelectionScheme& orig) { if(&orig != this) copy(orig); return *this; } virtual ~GASRSSelector() { delete [] fraction; delete [] choices; } virtual GASelectionScheme* clone() const { return new GASRSSelector; } virtual void copy(const GASelectionScheme& orig) { GASelectionScheme::copy(orig); const GASRSSelector& sel = DYN_CAST(const GASRSSelector&, orig); delete [] fraction; delete [] choices; n = sel.n; fraction = new float [n]; choices = new unsigned int [n]; memcpy(fraction, sel.fraction, n * sizeof(float)); memcpy(choices, sel.choices, n * sizeof(unsigned int)); } virtual GAGenome& select() const; virtual void update(); protected: float *fraction; unsigned int *choices; unsigned int n; }; #endif /* ---------------------------------------------------------------------------- Deterministic sampling selection. ---------------------------------------------------------------------------- */ #if USE_DS_SELECTOR == 1 class GADSSelector : public GASelectionScheme { public: GADefineIdentity("GADSSelector", GAID::DSSelection); GADSSelector(int w=GASelectionScheme::SCALED) : GASelectionScheme(w) { fraction = (float*)0; choices = (unsigned int *)0; idx = (unsigned int *)0; n = 0; } GADSSelector(const GADSSelector& orig) { fraction = (float*)0; choices = (unsigned int *)0; idx = (unsigned int *)0; n = 0; copy(orig); } GADSSelector& operator=(const GASelectionScheme& orig) { if(&orig != this) copy(orig); return *this; } virtual ~GADSSelector() { delete [] fraction; delete [] choices; delete [] idx; } virtual GASelectionScheme* clone() const { return new GADSSelector; } virtual void copy(const GASelectionScheme& orig) { GASelectionScheme::copy(orig); const GADSSelector& sel = DYN_CAST(const GADSSelector&, orig); delete [] fraction; delete [] choices; delete [] idx; n = sel.n; fraction = new float [n]; choices = new unsigned int [n]; idx = new unsigned int [n]; memcpy(fraction, sel.fraction, n * sizeof(float)); memcpy(choices, sel.choices, n * sizeof(unsigned int)); memcpy(idx, sel.idx, n * sizeof(unsigned int)); } virtual GAGenome& select() const; virtual void update(); protected: float *fraction; unsigned int *choices; unsigned int *idx; unsigned int n; }; #endif #endif galib247/ga/GASimpleGA.C0100644003643600364360000001477310573535473014022 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- gasimple.C mbwall 28jul94 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved Source file for the simple genetic algorithm object. ---------------------------------------------------------------------------- */ #include #include GAParameterList& GASimpleGA::registerDefaultParameters(GAParameterList& p) { GAGeneticAlgorithm::registerDefaultParameters(p); p.add(gaNelitism, gaSNelitism, GAParameter::BOOLEAN, &gaDefElitism); return p; } GASimpleGA::GASimpleGA(const GAGenome& c) : GAGeneticAlgorithm(c){ oldPop = pop->clone(); el = gaTrue; params.add(gaNelitism, gaSNelitism, GAParameter::BOOLEAN, &el); } GASimpleGA::GASimpleGA(const GAPopulation& p) : GAGeneticAlgorithm(p){ oldPop = pop->clone(); el = gaTrue; params.add(gaNelitism, gaSNelitism, GAParameter::BOOLEAN, &el); } GASimpleGA::GASimpleGA(const GASimpleGA& ga) : GAGeneticAlgorithm(ga){ oldPop = (GAPopulation *)0; copy(ga); } GASimpleGA::~GASimpleGA(){ delete oldPop; } GASimpleGA& GASimpleGA::operator=(const GASimpleGA& ga){ if(&ga != this) copy(ga); return *this; } void GASimpleGA::copy(const GAGeneticAlgorithm & g){ GAGeneticAlgorithm::copy(g); const GASimpleGA& ga = DYN_CAST(const GASimpleGA&,g); el = ga.el; if(oldPop) oldPop->copy(*(ga.oldPop)); else oldPop = ga.oldPop->clone(); oldPop->geneticAlgorithm(*this); } int GASimpleGA::setptr(const char* name, const void* value){ int status = GAGeneticAlgorithm::setptr(name, value); if(strcmp(name, gaNelitism) == 0 || strcmp(name, gaSNelitism) == 0){ el = (*((int*)value) != 0 ? gaTrue : gaFalse); status = 0; } return status; } int GASimpleGA::get(const char* name, void* value) const { int status = GAGeneticAlgorithm::get(name, value); if(strcmp(name, gaNelitism) == 0 || strcmp(name, gaSNelitism) == 0){ *((int*)value) = (el == gaTrue ? 1 : 0); status = 0; } return status; } void GASimpleGA::objectiveFunction(GAGenome::Evaluator f){ GAGeneticAlgorithm::objectiveFunction(f); for(int i=0; isize(); i++) oldPop->individual(i).evaluator(f); } void GASimpleGA::objectiveData(const GAEvalData& v){ GAGeneticAlgorithm::objectiveData(v); for(int i=0; isize(); i++) pop->individual(i).evalData(v); } const GAPopulation& GASimpleGA::population(const GAPopulation& p) { if(p.size() < 1) { GAErr(GA_LOC, className(), "population", gaErrNoIndividuals); return *pop; } GAGeneticAlgorithm::population(p); oldPop->copy(*pop->clone()); oldPop->geneticAlgorithm(*this); return *pop; } int GASimpleGA::populationSize(unsigned int n) { GAGeneticAlgorithm::populationSize(n); oldPop->size(n); return n; } int GASimpleGA::minimaxi(int m) { GAGeneticAlgorithm::minimaxi(m); if(m == MINIMIZE) oldPop->order(GAPopulation::LOW_IS_BEST); else oldPop->order(GAPopulation::HIGH_IS_BEST); return minmax; } // Initialize the population, set the random seed as needed, do a few stupidity // checks, reset the stats. We must initialize the old pop because there is no // guarantee that each individual will get initialized during the course of our // operator++ operations. We do not evaluate the old pop because that will // happen as-needed later on. void GASimpleGA::initialize(unsigned int seed) { GARandomSeed(seed); pop->initialize(); pop->evaluate(gaTrue); // the old pop will get it when the pops switch // oldPop->initialize(); stats.reset(*pop); if(!scross) GAErr(GA_LOC, className(), "initialize", gaErrNoSexualMating); } // Evolve a new generation of genomes. When we start this routine, pop // contains the current generation. When we finish, pop contains the new // generation and oldPop contains the (no longer) current generation. The // previous old generation is lost. We don't deallocate any memory, we just // reset the contents of the genomes. // The selection routine must return a pointer to a genome from the old // population. void GASimpleGA::step() { int i, mut, c1, c2; GAGenome *mom, *dad; // tmp holders for selected genomes GAPopulation *tmppop; // Swap the old population with the new pop. tmppop = oldPop; // When we finish the ++ we want the newly oldPop = pop; // generated population to be current (for pop = tmppop; // references to it from member functions). // Generate the individuals in the temporary population from individuals in // the main population. for(i=0; isize()-1; i+=2){ // takes care of odd population mom = &(oldPop->select()); dad = &(oldPop->select()); stats.numsel += 2; // keep track of number of selections c1 = c2 = 0; if(GAFlipCoin(pCrossover())){ stats.numcro += (*scross)(*mom, *dad, &pop->individual(i), &pop->individual(i+1)); c1 = c2 = 1; } else{ pop->individual( i ).copy(*mom); pop->individual(i+1).copy(*dad); } stats.nummut += (mut = pop->individual( i ).mutate(pMutation())); if(mut > 0) c1 = 1; stats.nummut += (mut = pop->individual(i+1).mutate(pMutation())); if(mut > 0) c2 = 1; stats.numeval += c1 + c2; } if(pop->size() % 2 != 0){ // do the remaining population member mom = &(oldPop->select()); dad = &(oldPop->select()); stats.numsel += 2; // keep track of number of selections c1 = 0; if(GAFlipCoin(pCrossover())){ stats.numcro += (*scross)(*mom, *dad, &pop->individual(i), (GAGenome*)0); c1 = 1; } else{ if(GARandomBit()) pop->individual( i ).copy(*mom); else pop->individual( i ).copy(*dad); } stats.nummut += (mut = pop->individual( i ).mutate(pMutation())); if(mut > 0) c1 = 1; stats.numeval += c1; } stats.numrep += pop->size(); pop->evaluate(gaTrue); // get info about current pop for next time // If we are supposed to be elitist, carry the best individual from the old // population into the current population. Be sure to check whether we are // supposed to minimize or maximize. if(minimaxi() == GAGeneticAlgorithm::MAXIMIZE) { if(el && oldPop->best().score() > pop->best().score()) oldPop->replace(pop->replace(&(oldPop->best()), GAPopulation::WORST), GAPopulation::BEST); } else { if(el && oldPop->best().score() < pop->best().score()) oldPop->replace(pop->replace(&(oldPop->best()), GAPopulation::WORST), GAPopulation::BEST); } stats.update(*pop); // update the statistics by one generation } galib247/ga/GASimpleGA.h0100644003643600364360000000451710573535473014062 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- gasimple.h mbwall 28jul94 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved Header file for the simple genetic algorithm class. ---------------------------------------------------------------------------- */ #ifndef _ga_gasimple_h_ #define _ga_gasimple_h_ #include class GASimpleGA : public GAGeneticAlgorithm { public: GADefineIdentity("GASimpleGA", GAID::SimpleGA); static GAParameterList& registerDefaultParameters(GAParameterList&); public: GASimpleGA(const GAGenome&); GASimpleGA(const GAPopulation&); GASimpleGA(const GASimpleGA&); GASimpleGA& operator=(const GASimpleGA&); virtual ~GASimpleGA(); virtual void copy(const GAGeneticAlgorithm&); virtual void initialize(unsigned int seed=0); virtual void step(); GASimpleGA & operator++() { step(); return *this; } virtual int setptr(const char* name, const void* value); virtual int get(const char* name, void* value) const; GABoolean elitist() const {return el;} GABoolean elitist(GABoolean flag) {params.set(gaNelitism, (int)flag); return el=flag;} virtual int minimaxi() const {return minmax;} virtual int minimaxi(int m); virtual const GAPopulation& population() const {return *pop;} virtual const GAPopulation& population(const GAPopulation&); virtual int populationSize() const {return pop->size();} virtual int populationSize(unsigned int n); virtual GAScalingScheme& scaling() const {return pop->scaling();} virtual GAScalingScheme& scaling(const GAScalingScheme & s) {oldPop->scaling(s); return GAGeneticAlgorithm::scaling(s);} virtual GASelectionScheme& selector() const {return pop->selector(); } virtual GASelectionScheme& selector(const GASelectionScheme& s) {oldPop->selector(s); return GAGeneticAlgorithm::selector(s);} virtual void objectiveFunction(GAGenome::Evaluator f); virtual void objectiveData(const GAEvalData& v); protected: GAPopulation *oldPop; // current and old populations GABoolean el; // are we elitist? }; #ifdef GALIB_USE_STREAMS inline STD_OSTREAM & operator<< (STD_OSTREAM & os, GASimpleGA & arg) { arg.write(os); return(os); } inline STD_ISTREAM & operator>> (STD_ISTREAM & is, GASimpleGA & arg) { arg.read(is); return(is); } #endif #endif galib247/ga/GASStateGA.C0100644003643600364360000002331710573535474013767 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- gasteadystate.C mbwall 28jul94 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved Souce file for the steady-state genetic algorithm object. ---------------------------------------------------------------------------- */ #include #include //#define GA_DEBUG #define USE_PREPL 0 #define USE_NREPL 1 GAParameterList& GASteadyStateGA::registerDefaultParameters(GAParameterList& p) { GAGeneticAlgorithm::registerDefaultParameters(p); int ival = 1; p.add(gaNnReplacement, gaSNnReplacement, GAParameter::INT, &ival); p.add(gaNpReplacement, gaSNpReplacement, GAParameter::FLOAT, &gaDefPRepl); p.set(gaNscoreFrequency, gaDefScoreFrequency2); return p; } GASteadyStateGA::GASteadyStateGA(const GAGenome& c) : GAGeneticAlgorithm(c) { pRepl = gaDefPRepl; params.add(gaNpReplacement, gaSNpReplacement, GAParameter::FLOAT, &pRepl); float n = ((pRepl*(float)pop->size() < 1) ? 1 : pRepl*(float)pop->size()); tmpPop = new GAPopulation(pop->individual(0), (unsigned int)n); nRepl = tmpPop->size(); params.add(gaNnReplacement, gaSNnReplacement, GAParameter::INT, &nRepl); stats.scoreFrequency(gaDefScoreFrequency2); params.set(gaNscoreFrequency, gaDefScoreFrequency2); which = USE_PREPL; } GASteadyStateGA::GASteadyStateGA(const GAPopulation& p): GAGeneticAlgorithm(p){ pRepl = gaDefPRepl; params.add(gaNpReplacement, gaSNpReplacement, GAParameter::FLOAT, &pRepl); float n = ((pRepl*(float)pop->size() < 1) ? 1 : pRepl*(float)pop->size()); tmpPop = new GAPopulation(pop->individual(0), (unsigned int)n); nRepl = tmpPop->size(); params.add(gaNnReplacement, gaSNnReplacement, GAParameter::INT, &nRepl); stats.scoreFrequency(gaDefScoreFrequency2); params.set(gaNscoreFrequency, gaDefScoreFrequency2); which = USE_PREPL; } GASteadyStateGA::GASteadyStateGA(const GASteadyStateGA& ga) : GAGeneticAlgorithm(ga) { tmpPop = (GAPopulation *)0; copy(ga); } GASteadyStateGA::~GASteadyStateGA(){ delete tmpPop; } GASteadyStateGA& GASteadyStateGA::operator=(const GASteadyStateGA& ga){ if(&ga != this) copy(ga); return *this; } void GASteadyStateGA::copy(const GAGeneticAlgorithm & g){ GAGeneticAlgorithm::copy(g); const GASteadyStateGA& ga = DYN_CAST(const GASteadyStateGA&, g); pRepl = ga.pRepl; nRepl = ga.nRepl; if(tmpPop) tmpPop->copy(*(ga.tmpPop)); else tmpPop = ga.tmpPop->clone(); tmpPop->geneticAlgorithm(*this); which = ga.which; } int GASteadyStateGA::setptr(const char* name, const void* value){ int status = GAGeneticAlgorithm::setptr(name, value); if(strcmp(name, gaNpReplacement) == 0 || strcmp(name, gaSNpReplacement) == 0){ #ifdef GA_DEBUG cerr << "GAGeneticAlgorithm::setptr\n setting '" << name << "' to '" << *((float*)value) << "'\n"; #endif pReplacement(*((float*)value)); status = 0; } else if(strcmp(name, gaNnReplacement) == 0 || strcmp(name, gaSNnReplacement) == 0){ #ifdef GA_DEBUG cerr << "GAGeneticAlgorithm::setptr\n setting '" << name << "' to '" << *((int*)value) << "'\n"; #endif nReplacement(*((int*)value)); status = 0; } return status; } int GASteadyStateGA::get(const char* name, void* value) const { int status = GAGeneticAlgorithm::get(name, value); if(strcmp(name, gaNpReplacement) == 0 || strcmp(name, gaSNpReplacement) == 0){ *((float*)value) = pRepl; status = 0; } else if(strcmp(name, gaNnReplacement) == 0 || strcmp(name, gaSNnReplacement) == 0){ *((int*)value) = nRepl; status = 0; } return status; } void GASteadyStateGA::objectiveFunction(GAGenome::Evaluator f){ GAGeneticAlgorithm::objectiveFunction(f); for(int i=0; isize(); i++) tmpPop->individual(i).evaluator(f); } void GASteadyStateGA::objectiveData(const GAEvalData& v){ GAGeneticAlgorithm::objectiveData(v); for(int i=0; isize(); i++) tmpPop->individual(i).evalData(v); } const GAPopulation& GASteadyStateGA::population(const GAPopulation& p) { if(p.size() < 1) { GAErr(GA_LOC, className(), "population", gaErrNoIndividuals); return *pop; } GAGeneticAlgorithm::population(p); delete tmpPop; if(which == USE_PREPL){ float n = pRepl * pop->size(); if(n < 1) n = 1.0; nRepl = (unsigned int)n; params.set(gaNnReplacement, nRepl); } else{ if(nRepl > (unsigned int)(pop->size())) nRepl = pop->size(); if(nRepl < 1) nRepl = 1; } tmpPop = new GAPopulation(pop->individual(0), nRepl); tmpPop->geneticAlgorithm(*this); return *pop; } int GASteadyStateGA::populationSize(unsigned int value){ GAGeneticAlgorithm::populationSize(value); if(which == USE_PREPL){ float n = ((pRepl*(float)pop->size() < 1) ? 1 : pRepl*(float)pop->size()); nRepl = (unsigned int)n; params.set(gaNnReplacement, (unsigned int)nRepl); tmpPop->size(nRepl); } else { // if we're using nrepl, be sure in valid range if(nRepl > value) { // clip to new population size nRepl = value; tmpPop->size(nRepl); } } return value; } // If we get a value of 0 for either of these, this means to use the other // measure instead. float GASteadyStateGA::pReplacement(float value){ if(value == pRepl) return pRepl; if(value <= 0 || value > 1){ GAErr(GA_LOC, className(), "pReplacement", gaErrBadPRepl); params.set(gaNpReplacement, pRepl); // force it back return pRepl; } params.set(gaNpReplacement, (double)value); pRepl = value; float n = ((value*(float)pop->size() < 1) ? 1 : value*(float)pop->size()); nRepl = (unsigned int)n; params.set(gaNnReplacement, (unsigned int)nRepl); which = USE_PREPL; tmpPop->size(nRepl); return pRepl; } int GASteadyStateGA::nReplacement(unsigned int value){ if(value == nRepl) return nRepl; if(value == 0 || value > (unsigned int)(pop->size())){ GAErr(GA_LOC, className(), "nReplacement", gaErrBadNRepl); params.set(gaNnReplacement, nRepl); // force it back return nRepl; } params.set(gaNnReplacement, (unsigned int)value); nRepl = value; pRepl = (float)nRepl / (float)pop->size(); params.set(gaNpReplacement, (double)pRepl); which = USE_NREPL; tmpPop->size(nRepl); return nRepl; } int GASteadyStateGA::minimaxi(int m) { GAGeneticAlgorithm::minimaxi(m); if(m == MINIMIZE) tmpPop->order(GAPopulation::LOW_IS_BEST); else tmpPop->order(GAPopulation::HIGH_IS_BEST); return minmax; } // For initialization we set the random seed, check for stupid errors, init the // population, reset the statistics, and that's it. // If we don't get a seed then we set it ourselves. If we do get one, then // we use it as the random seed. void GASteadyStateGA::initialize(unsigned int seed) { GARandomSeed(seed); pop->initialize(); pop->evaluate(gaTrue); stats.reset(*pop); if(!scross) GAErr(GA_LOC, className(), "initialize", gaErrNoSexualMating); } // Evolve a new generation of genomes. A steady-state GA has no 'old' // and 'new' populations - we pick from the current population and replace its // members with the new ones we create. We replace the worst members of the // preceeding population. If a genome in the tmp population is worse than // one in the main population, the genome in the main population will be // replaced regardless of its better score. void GASteadyStateGA::step() { int i, mut, c1, c2; GAGenome *mom, *dad; // tmp holders for selected genomes // Generate the individuals in the temporary population from individuals in // the main population. for(i=0; isize()-1; i+=2){ // takes care of odd population mom = &(pop->select()); dad = &(pop->select()); stats.numsel += 2; // keep track of number of selections c1 = c2 = 0; if(GAFlipCoin(pCrossover())){ stats.numcro += (*scross)(*mom, *dad, &tmpPop->individual(i), &tmpPop->individual(i+1)); c1 = c2 = 1; } else{ tmpPop->individual( i ).copy(*mom); tmpPop->individual(i+1).copy(*dad); } stats.nummut += (mut = tmpPop->individual( i ).mutate(pMutation())); if(mut > 0) c1 = 1; stats.nummut += (mut = tmpPop->individual(i+1).mutate(pMutation())); if(mut > 0) c2 = 1; stats.numeval += c1 + c2; } if(tmpPop->size() % 2 != 0){ // do the remaining population member mom = &(pop->select()); dad = &(pop->select()); stats.numsel += 2; // keep track of number of selections c1 = 0; if(GAFlipCoin(pCrossover())){ stats.numcro += (*scross)(*mom, *dad, &tmpPop->individual(i), (GAGenome*)0); c1 = 1; } else{ if(GARandomBit()) tmpPop->individual( i ).copy(*mom); else tmpPop->individual( i ).copy(*dad); } stats.nummut += (mut = tmpPop->individual( i ).mutate(pMutation())); if(mut > 0) c1 = 1; stats.numeval += c1; } // Replace the worst genomes in the main population with all of the individuals // we just created. Notice that we invoke the population's add member with a // genome pointer rather than reference. This way we don't force a clone of // the genome - we just let the population take over. Then we take it back by // doing a remove then a replace in the tmp population. for(i=0; isize(); i++) pop->add(&tmpPop->individual(i)); pop->evaluate(); // get info about current pop for next time pop->scale(); // remind the population to do its scaling // the individuals in tmpPop are all owned by pop, but tmpPop does not know // that. so we use replace to take the individuals from the pop and stick // them back into tmpPop for(i=0; isize(); i++) tmpPop->replace(pop->remove(GAPopulation::WORST, GAPopulation::SCALED), i); stats.numrep += tmpPop->size(); stats.update(*pop); // update the statistics by one generation } galib247/ga/GASStateGA.h0100644003643600364360000000514010573535473014025 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- gasteadystate.h mbwall 28jul94 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved Header file for the steady-state genetic algorithm class. ---------------------------------------------------------------------------- */ #ifndef _ga_gasteadystate_h_ #define _ga_gasteadystate_h_ #include class GASteadyStateGA : public GAGeneticAlgorithm { public: GADefineIdentity("GASteadyStateGA", GAID::SteadyStateGA); static GAParameterList& registerDefaultParameters(GAParameterList&); public: GASteadyStateGA(const GAGenome&); GASteadyStateGA(const GAPopulation&); GASteadyStateGA(const GASteadyStateGA&); GASteadyStateGA& operator=(const GASteadyStateGA&); virtual ~GASteadyStateGA(); virtual void copy(const GAGeneticAlgorithm&); virtual void initialize(unsigned int seed=0); virtual void step(); GASteadyStateGA & operator++() { step(); return *this; } virtual int setptr(const char* name, const void* value); virtual int get(const char* name, void* value) const; virtual int minimaxi() const {return minmax;} virtual int minimaxi(int m); virtual const GAPopulation& population() const {return *pop;} virtual const GAPopulation& population(const GAPopulation&); virtual int populationSize() const {return pop->size();} virtual int populationSize(unsigned int n); virtual GAScalingScheme& scaling() const {return pop->scaling();} virtual GAScalingScheme& scaling(const GAScalingScheme & s) { /* tmpPop->scaling(s); */ return GAGeneticAlgorithm::scaling(s); } virtual GASelectionScheme& selector() const {return pop->selector(); } virtual GASelectionScheme& selector(const GASelectionScheme& s) { /* tmpPop->selector(s); */ return GAGeneticAlgorithm::selector(s); } virtual void objectiveFunction(GAGenome::Evaluator f); virtual void objectiveData(const GAEvalData& v); float pReplacement() const { return pRepl; } float pReplacement(float p); int nReplacement() const { return nRepl; } int nReplacement(unsigned int n); protected: GAPopulation *tmpPop; // temporary population for replacements float pRepl; // percentage of population to replace each gen unsigned int nRepl; // how many of each population to replace short which; // 0 if prepl, 1 if nrepl }; #ifdef GALIB_USE_STREAMS inline STD_OSTREAM & operator<< (STD_OSTREAM & os, GASteadyStateGA & arg) { arg.write(os); return(os); } inline STD_ISTREAM & operator>> (STD_ISTREAM & is, GASteadyStateGA & arg) { arg.read(is); return(is); } #endif #endif galib247/ga/GAStatistics.C0100644003643600364360000004362210573535473014506 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- statistics.C mbwall 28jul94 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved DESCRIPTION: Definition of the statistics object. ---------------------------------------------------------------------------- */ #include #include #include // Default settings and their names. int gaDefNumBestGenomes = 1; int gaDefScoreFrequency1 = 1; int gaDefScoreFrequency2 = 100; int gaDefFlushFrequency = 0; char gaDefScoreFilename[] = "generations.dat"; GAStatistics::GAStatistics() { curgen = 0; numsel = numcro = nummut = numrep = numeval = numpeval = 0; maxever = minever = 0.0; on = offmax = offmin = 0.0; aveInit = maxInit = minInit = devInit = 0.0; divInit = -1.0; aveCur = maxCur = minCur = devCur = 0.0; divCur = -1.0; scoreFreq = gaDefScoreFrequency1; dodiv = gaFalse; // default is do not calculate diversity nconv=0; Nconv = 10; cscore = new float[Nconv]; memset(cscore, 0, Nconv*sizeof(float)); nscrs=0; Nscrs = gaDefFlushFrequency; gen = new int[Nscrs]; memset(gen, 0, Nscrs*sizeof(int)); aveScore = new float[Nscrs]; memset(aveScore, 0, Nscrs*sizeof(float)); maxScore = new float[Nscrs]; memset(maxScore, 0, Nscrs*sizeof(float)); minScore = new float[Nscrs]; memset(minScore, 0, Nscrs*sizeof(float)); devScore = new float[Nscrs]; memset(devScore, 0, Nscrs*sizeof(float)); divScore = new float[Nscrs]; memset(divScore, 0, Nscrs*sizeof(float)); scorefile = new char[strlen(gaDefScoreFilename)+1]; strcpy(scorefile, gaDefScoreFilename); which = Maximum; boa = (GAPopulation *)0; } GAStatistics::GAStatistics(const GAStatistics & orig){ cscore=(float *)0; gen=(int *)0; aveScore=(float *)0; maxScore=(float *)0; minScore=(float *)0; devScore=(float *)0; divScore=(float *)0; scorefile=(char *)0; boa=(GAPopulation *)0; copy(orig); } GAStatistics::~GAStatistics(){ delete [] cscore; delete [] gen; delete [] aveScore; delete [] maxScore; delete [] minScore; delete [] devScore; delete [] divScore; delete [] scorefile; delete boa; } void GAStatistics::copy(const GAStatistics & orig){ if(&orig == this) return; curgen = orig.curgen; numsel = orig.numsel; numcro = orig.numcro; nummut = orig.nummut; numrep = orig.numrep; numeval = orig.numeval; numpeval = orig.numpeval; maxever = orig.maxever; minever = orig.minever; on = orig.on; offmax = orig.offmax; offmin = orig.offmin; aveInit = orig.aveInit; maxInit = orig.maxInit; minInit = orig.minInit; devInit = orig.devInit; divInit = orig.divInit; aveCur = orig.aveCur; maxCur = orig.maxCur; minCur = orig.minCur; devCur = orig.devCur; divCur = orig.divCur; scoreFreq = orig.scoreFreq; dodiv = orig.dodiv; nconv=orig.nconv; Nconv=orig.Nconv; delete [] cscore; cscore = new float [Nconv]; memcpy(cscore, orig.cscore, Nconv*sizeof(float)); nscrs=orig.nscrs; Nscrs=orig.Nscrs; delete [] gen; gen = new int [Nscrs]; memcpy(gen, orig.gen, Nscrs*sizeof(int)); delete [] aveScore; aveScore = new float [Nscrs]; memcpy(aveScore, orig.aveScore, Nscrs*sizeof(float)); delete [] maxScore; maxScore = new float [Nscrs]; memcpy(maxScore, orig.maxScore, Nscrs*sizeof(float)); delete [] minScore; minScore = new float [Nscrs]; memcpy(minScore, orig.minScore, Nscrs*sizeof(float)); delete [] devScore; devScore = new float [Nscrs]; memcpy(devScore, orig.devScore, Nscrs*sizeof(float)); delete [] divScore; divScore = new float [Nscrs]; memcpy(divScore, orig.divScore, Nscrs*sizeof(float)); delete [] scorefile; if(orig.scorefile){ scorefile = new char [strlen(orig.scorefile)+1]; strcpy(scorefile, orig.scorefile); } else scorefile = (char*)0; which = orig.which; delete boa; if(orig.boa) boa = orig.boa->clone(); } // Update the genomes in the 'best of all' population to reflect any // changes made to the current population. We just grab the genomes with // the highest scores from the current population, and if they are higher than // those of the genomes in the boa population, they get copied. Note that // the bigger the boa array, the bigger your running performance hit because // we have to look through all of the boa to figure out which are better than // those in the population. The fastest way to use the boa is to keep only // one genome in the boa population. A flag of 'True' will reset the boa // population so that it is filled with the best of the current population. // Unfortunately it could take a long time to update the boa array using the // copy method. We'd like to simply keep pointers to the best genomes, but // the genomes change from generation to generation, so we can't depend on // that. // Notice that keeping boa is useful even for overlapping populations. The // boa keeps individuals that are different from each other - the overlapping // population may not. However, keeping boa is most useful for populations // with little overlap. // When we check to see if a potentially better member is already in our // best-of-all population, we use the operator== comparator not the genome // comparator to do the comparison. void GAStatistics:: updateBestIndividual(const GAPopulation & pop, GABoolean flag){ if(boa == (GAPopulation *)0 || boa->size() == 0) return; // do nothing if(pop.order() != boa->order()) boa->order(pop.order()); if(flag == gaTrue){ // reset the BOA array int j=0; for(int i=0; isize(); i++){ boa->best(i).copy(pop.best(j)); if(j < pop.size()-1) j++; } return; } if(boa->size() == 1){ // there's only one boa so replace it with bop if(boa->order() == GAPopulation::HIGH_IS_BEST && pop.best().score() > boa->best().score()) boa->best().copy(pop.best()); if(boa->order() == GAPopulation::LOW_IS_BEST && pop.best().score() < boa->best().score()) boa->best().copy(pop.best()); } else{ int i=0, j, k; if(boa->order() == GAPopulation::HIGH_IS_BEST) { while(i < pop.size() && pop.best(i).score() > boa->worst().score()){ for(k=0; pop.best(i).score() < boa->best(k).score() && k < boa->size(); k++); for(j=k; jsize(); j++){ if(pop.best(i) == boa->best(j)) break; if(pop.best(i).score() > boa->best(j).score()){ boa->worst().copy(pop.best(i)); // replace worst individual boa->sort(gaTrue, GAPopulation::RAW); // re-sort the population break; } } i++; } } if(boa->order() == GAPopulation::LOW_IS_BEST) { while(i < pop.size() && pop.best(i).score() < boa->worst().score()){ for(k=0; pop.best(i).score() > boa->best(k).score() && k < boa->size(); k++); for(j=k; jsize(); j++){ if(pop.best(i) == boa->best(j)) break; if(pop.best(i).score() < boa->best(j).score()){ boa->worst().copy(pop.best(i)); // replace worst individual boa->sort(gaTrue, GAPopulation::RAW); // re-sort the population break; } } i++; } } } return; } // Use this method to update the statistics to account for the current // population. This routine increments the generation counter and assumes that // the population that gets passed is the current population. // If we are supposed to flush the scores, then we dump them to the specified // file. If no flushing frequency has been specified then we don't record. void GAStatistics::update(const GAPopulation & pop){ ++curgen; // must do this first so no divide-by-zero if(scoreFreq > 0 && (curgen % scoreFreq == 0)) setScore(pop); if(Nscrs > 0 && nscrs >= Nscrs) flushScores(); maxever = (pop.max() > maxever) ? pop.max() : maxever; minever = (pop.min() < minever) ? pop.min() : minever; float tmpval; tmpval = (on*(curgen-1) + pop.ave()) / curgen; on = tmpval; tmpval = (offmax*(curgen-1) + pop.max()) / curgen; offmax = tmpval; tmpval = (offmin*(curgen-1) + pop.min()) / curgen; offmin = tmpval; setConvergence((pop.order() == GAPopulation::HIGH_IS_BEST) ? pop.max() : pop.min()); updateBestIndividual(pop); numpeval = pop.nevals(); } // Reset the GA's statistics based on the population. To do this right you // should initialize the population before you pass it to this routine. If you // don't, the stats will be based on a non-initialized population. void GAStatistics::reset(const GAPopulation & pop){ curgen = 0; numsel = numcro = nummut = numrep = numeval = numpeval = 0; memset(gen, 0, Nscrs*sizeof(int)); memset(aveScore, 0, Nscrs*sizeof(float)); memset(maxScore, 0, Nscrs*sizeof(float)); memset(minScore, 0, Nscrs*sizeof(float)); memset(devScore, 0, Nscrs*sizeof(float)); memset(divScore, 0, Nscrs*sizeof(float)); nscrs = 0; setScore(pop); if(Nscrs > 0) flushScores(); memset(cscore, 0, Nconv*sizeof(float)); nconv = 0; // should set to -1 then call setConv cscore[0] = ((pop.order() == GAPopulation::HIGH_IS_BEST) ? pop.max() : pop.min()); // cscore[0] = pop.max(); // setConvergence(maxScore[0]); updateBestIndividual(pop, gaTrue); aveCur = aveInit = pop.ave(); maxCur = maxInit = maxever = pop.max(); minCur = minInit = minever = pop.min(); devCur = devInit = pop.dev(); divCur = divInit = ((dodiv == gaTrue) ? pop.div() : (float)-1.0); on = pop.ave(); offmax = pop.max(); offmin = pop.min(); numpeval = pop.nevals(); for(int i=0; isize(n); } return n; } const GAGenome & GAStatistics::bestIndividual(unsigned int n) const { if(boa == 0 || (int)n >= boa->size()){ GAErr(GA_LOC, "GAStatistics", "bestIndividual", gaErrBadPopIndex); n = 0; } return boa->best(n); // this will crash if no boa } // Adjust the scores buffers to match the specified amount. If someone // specifies zero then we don't keep the scores, so set all to NULL. int GAStatistics::flushFrequency(unsigned int freq){ if(freq == 0){ if(nscrs > 0) flushScores(); resizeScores(freq); } else if(freq > Nscrs){ resizeScores(freq); } else if(freq < Nscrs){ if(nscrs > freq) flushScores(); resizeScores(freq); } Nscrs = freq; return freq; } // Resize the scores vectors to the specified amount. Copy any scores that // exist. void GAStatistics::resizeScores(unsigned int n){ int *tmpi; float *tmpf; if(n == 0){ delete [] gen; gen = (int*)0; delete [] aveScore; aveScore = (float*)0; delete [] maxScore; maxScore = (float*)0; delete [] minScore; minScore = (float*)0; delete [] devScore; devScore = (float*)0; delete [] divScore; divScore = (float*)0; nscrs = n; } else{ tmpi = gen; gen = new int [n]; memcpy(gen, tmpi, (n < Nscrs ? n : Nscrs)*sizeof(int)); delete [] tmpi; tmpf = aveScore; aveScore = new float [n]; memcpy(aveScore, tmpf, (n < Nscrs ? n : Nscrs)*sizeof(float)); delete [] tmpf; tmpf = maxScore; maxScore = new float [n]; memcpy(maxScore, tmpf, (n < Nscrs ? n : Nscrs)*sizeof(float)); delete [] tmpf; tmpf = minScore; minScore = new float [n]; memcpy(minScore, tmpf, (n < Nscrs ? n : Nscrs)*sizeof(float)); delete [] tmpf; tmpf = devScore; devScore = new float [n]; memcpy(devScore, tmpf, (n < Nscrs ? n : Nscrs)*sizeof(float)); delete [] tmpf; tmpf = divScore; divScore = new float [n]; memcpy(divScore, tmpf, (n < Nscrs ? n : Nscrs)*sizeof(float)); delete [] tmpf; if(nscrs > n) nscrs = n; } Nscrs = n; } // Write the current scores to file. If this is the first chunk (ie gen[0] // is 0) then we create a new file. Otherwise we append to an existing file. // We give no notice that we're overwriting the existing file!! void GAStatistics::writeScores(){ if(!scorefile) return; #ifdef GALIB_USE_STREAMS STD_OFSTREAM outfile(scorefile, ((gen[0] == 0) ? (STD_IOS_OUT | STD_IOS_TRUNC) : (STD_IOS_OUT | STD_IOS_APP))); // should be done this way, but SGI systems (and others?) don't do it right... // if(! outfile.is_open()){ if(outfile.fail()){ GAErr(GA_LOC, "GAStatistics", "writeScores", gaErrWriteError, scorefile); return; } scores(outfile, which); outfile.close(); #endif } #ifdef GALIB_USE_STREAMS int GAStatistics::write(const char* filename) const { STD_OFSTREAM outfile(filename, (STD_IOS_OUT | STD_IOS_TRUNC)); // should be done this way, but SGI systems (and others?) don't do it right... // if(! outfile.is_open()){ if(outfile.fail()){ GAErr(GA_LOC, "GAStatistics", "write", gaErrWriteError, filename); return 1; } write(outfile); outfile.close(); return 0; } int GAStatistics::write(STD_OSTREAM & os) const { os << curgen << "\t# current generation\n"; os << convergence() << "\t# current convergence\n"; os << numsel << "\t# number of selections since initialization\n"; os << numcro << "\t# number of crossovers since initialization\n"; os << nummut << "\t# number of mutations since initialization\n"; os << numrep << "\t# number of replacements since initialization\n"; os << numeval << "\t# number of genome evaluations since initialization\n"; os << numpeval << "\t# number of population evaluations since initialization\n"; os << maxever << "\t# maximum score since initialization\n"; os << minever << "\t# minimum score since initialization\n"; os << on << "\t# average of all scores ('on-line' performance)\n"; os << offmax << "\t# average of maximum scores ('off-line' performance)\n"; os << offmin << "\t# average of minimum scores ('off-line' performance)\n"; os << "\n"; os << aveInit << "\t# mean score in initial population\n"; os << maxInit << "\t# maximum score in initial population\n"; os << minInit << "\t# minimum score in initial population\n"; os << devInit << "\t# standard deviation of initial population\n"; os < #include #include #include // Default settings and their names. extern int gaDefNumBestGenomes; extern int gaDefScoreFrequency1; extern int gaDefScoreFrequency2; extern int gaDefFlushFrequency; extern char gaDefScoreFilename[]; /* ---------------------------------------------------------------------------- Statistics class We define this class as a storage object for the current state of the GA. Whereas the parameters object keeps track of the user-definable settings for the GA, the statistics object keeps track of the data that the GA generates along the way. ---------------------------------------------------------------------------- */ class GAStatistics { public: enum { NoScores=0x00, Mean=0x01, Maximum=0x02, Minimum=0x04, Deviation=0x08, Diversity=0x10, AllScores=0xff }; GAStatistics(); GAStatistics(const GAStatistics&); GAStatistics& operator=(const GAStatistics& orig){copy(orig); return *this;} virtual ~GAStatistics(); void copy(const GAStatistics &); float online() const {return on;} float offlineMax() const {return offmax;} float offlineMin() const {return offmin;} float initial(int w=Maximum) const; float current(int w=Maximum) const; float maxEver() const {return maxever;} float minEver() const {return minever;} int generation() const {return curgen;} unsigned long int selections() const {return numsel;} unsigned long int crossovers() const {return numcro;} unsigned long int mutations() const {return nummut;} unsigned long int replacements() const {return numrep;} unsigned long int indEvals() const {return numeval;} unsigned long int popEvals() const {return numpeval;} float convergence() const; int nConvergence() const { return Nconv; } int nConvergence(unsigned int); int nBestGenomes(const GAGenome&, unsigned int); int nBestGenomes() const { return(boa ? boa->size() : 0); } int scoreFrequency(unsigned int x) { return(scoreFreq = x); } int scoreFrequency() const { return scoreFreq; } int flushFrequency(unsigned int x); int flushFrequency() const { return Nscrs; } const char* scoreFilename(const char *filename); const char* scoreFilename() const { return scorefile; } int selectScores(int w){ return which = w; } int selectScores() const { return which; } GABoolean recordDiversity(GABoolean flag){ return dodiv=flag; } GABoolean recordDiversity() const { return dodiv; } void flushScores(); void update(const GAPopulation & pop); void reset(const GAPopulation & pop); const GAPopulation & bestPopulation() const { return *boa; } const GAGenome & bestIndividual(unsigned int n=0) const; #ifdef GALIB_USE_STREAMS int scores(const char* filename, int which=NoScores); int scores(STD_OSTREAM & os, int which=NoScores); int write(const char* filename) const; int write(STD_OSTREAM & os) const; #endif // These should be protected (accessible only to the GA class) but for now they // are publicly accessible. Do not try to set these unless you know what you // are doing!! unsigned long int numsel; // number of selections since reset unsigned long int numcro; // number of crossovers since reset unsigned long int nummut; // number of mutations since reset unsigned long int numrep; // number of replacements since reset unsigned long int numeval; // number of individual evaluations since reset unsigned long int numpeval; // number of population evals since reset protected: unsigned int curgen; // current generation number unsigned int scoreFreq; // how often (in generations) to record scores GABoolean dodiv; // should we record diversity? float maxever; // maximum score since initialization float minever; // minimum score since initialization float on; // "on-line" performance (ave of all scores) float offmax; // "off-line" performance (ave of maximum) float offmin; // "off-line" performance (ave of minimum) float aveInit; // stats from the initial population float maxInit; float minInit; float devInit; float divInit; float aveCur; // stats from the current population float maxCur; float minCur; float devCur; float divCur; unsigned int nconv, Nconv; // how many scores we're recording (flushFreq) float * cscore; // best score of last n generations unsigned int nscrs, Nscrs; // how many scores do we have? int * gen; // generation number corresponding to scores float * aveScore; // average scores of each generation float * maxScore; // best scores of each generation float * minScore; // worst scores of each generation float * devScore; // stddev of each generation float * divScore; // diversity of each generation char * scorefile; // name of file to which scores get written int which; // which data to write to file GAPopulation * boa; // keep a copy of the best genomes void setConvergence(float); void setScore(const GAPopulation&); void updateBestIndividual(const GAPopulation&, GABoolean flag=gaFalse); void writeScores(); void resizeScores(unsigned int); friend class GA; }; inline const char* GAStatistics::scoreFilename(const char* filename){ delete [] scorefile; scorefile = 0; if(filename){ scorefile = new char[strlen(filename)+1]; strcpy(scorefile, filename); } return scorefile; } inline float GAStatistics::convergence() const { double cnv = 0.0; if(nconv >= Nconv-1 && cscore[nconv%Nconv] != 0) cnv = (double)(cscore[(nconv+1)%Nconv]) / (double)(cscore[nconv%Nconv]); return (float)cnv; } inline float GAStatistics::initial(int w) const { float val = 0.0; switch(w){ case Mean: val = aveInit; break; case Maximum: val = maxInit; break; case Minimum: val = minInit; break; case Deviation: val = devInit; break; case Diversity: val = divInit; break; default: break; } return val; } inline float GAStatistics::current(int w) const { float val = 0.0; switch(w){ case Mean: val = aveCur; break; case Maximum: val = maxCur; break; case Minimum: val = minCur; break; case Deviation: val = devCur; break; case Diversity: val = divCur; break; default: break; } return val; } #ifdef GALIB_USE_STREAMS inline STD_OSTREAM & operator<< (STD_OSTREAM & os, const GAStatistics& s) { s.write(os); return os; } #endif #endif galib247/ga/GAStringGenome.C0100644003643600364360000000643210573535473014753 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- string.C mbwall 21mar95 Copyright (c) 1995-1996 Massachusetts Institute of Technology all rights reserved DESCRIPTION: Source file for the string specialization of the array genome. ---------------------------------------------------------------------------- */ #include template <> const char * GA1DArrayAlleleGenome::className() const {return "GAStringGenome";} template <> int GA1DArrayAlleleGenome::classID() const {return GAID::StringGenome;} template <> GA1DArrayAlleleGenome:: GA1DArrayAlleleGenome(unsigned int length, const GAAlleleSet & s, GAGenome::Evaluator f, void * u) : GA1DArrayGenome(length, f, u){ naset = 1; aset = new GAAlleleSet[1]; aset[0] = s; initializer(DEFAULT_STRING_INITIALIZER); mutator(DEFAULT_STRING_MUTATOR); comparator(DEFAULT_STRING_COMPARATOR); crossover(DEFAULT_STRING_CROSSOVER); } template <> GA1DArrayAlleleGenome:: GA1DArrayAlleleGenome(const GAAlleleSetArray & sa, GAGenome::Evaluator f, void * u) : GA1DArrayGenome(sa.size(), f, u){ naset = sa.size(); aset = new GAAlleleSet[naset]; for(int i=0; i GA1DArrayAlleleGenome::~GA1DArrayAlleleGenome(){ delete [] aset; } #ifdef GALIB_USE_STREAMS // The read specialization takes in each character whether it is whitespace or // not and stuffs it into the genome. This is unlike the default array read. template <> int GA1DArrayAlleleGenome::read(STD_ISTREAM & is) { unsigned int i=0; char c; do{ is.get(c); if(!is.fail()) gene(i++, c); } while(!is.fail() && !is.eof() && i < nx); if(is.eof() && i < nx){ GAErr(GA_LOC, className(), "read", gaErrUnexpectedEOF); is.clear(STD_IOS_BADBIT | is.rdstate()); return 1; } return 0; } // Unlike the base array genome, here when we write out we don't put any // whitespace between genes. No newline at end of it all. template <> int GA1DArrayAlleleGenome::write(STD_OSTREAM & os) const { for(unsigned int i=0; i #include #if defined(__BORLANDC__) #define GALIB_STRINGGENOME_TEMPLATE_PREFACE #else #define GALIB_STRINGGENOME_TEMPLATE_PREFACE template class #endif GALIB_STRINGGENOME_TEMPLATE_PREFACE GAAlleleSet; GALIB_STRINGGENOME_TEMPLATE_PREFACE GAAlleleSetCore; GALIB_STRINGGENOME_TEMPLATE_PREFACE GAAlleleSetArray; GALIB_STRINGGENOME_TEMPLATE_PREFACE GAArray; GALIB_STRINGGENOME_TEMPLATE_PREFACE GA1DArrayGenome; GALIB_STRINGGENOME_TEMPLATE_PREFACE GA1DArrayAlleleGenome; #endif galib247/ga/GAStringGenome.h0100644003643600364360000000475610573535474015030 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- string.h mbwall 25feb95 Copyright (c) 1995 Massachusetts Institute of Technology DESCRIPTION: This header defines the interface for the string genome. ---------------------------------------------------------------------------- */ #ifndef _ga_string_h_ #define _ga_string_h_ #include #include typedef GAAlleleSet GAStringAlleleSet; typedef GAAlleleSet GACharacterAlleleSet; typedef GAAlleleSetArray GAStringAlleleSetArray; typedef GA1DArrayAlleleGenome GAStringGenome; // in one (and only one) place in the code that uses the string genome, you // should define INSTANTIATE_STRING_GENOME in order to force the specialization // for this genome. #if defined(INSTANTIATE_STRING_GENOME) #include #endif inline void GAStringUniformInitializer(GAGenome& g){ GA1DArrayAlleleGenome::UniformInitializer(g); } inline void GAStringOrderedInitializer(GAGenome& g){ GA1DArrayAlleleGenome::OrderedInitializer(g); } inline int GAStringFlipMutator(GAGenome& g, float pmut){ return GA1DArrayAlleleGenome::FlipMutator(g, pmut); } inline int GAStringSwapMutator(GAGenome& g, float pmut){ return GA1DArrayGenome::SwapMutator(g, pmut); } inline int GAStringUniformCrossover(const GAGenome& a, const GAGenome& b, GAGenome* c, GAGenome* d) { return GA1DArrayGenome::UniformCrossover(a,b,c,d); } inline int GAStringEvenOddCrossover(const GAGenome& a, const GAGenome& b, GAGenome* c, GAGenome* d) { return GA1DArrayGenome::EvenOddCrossover(a,b,c,d); } inline int GAStringOnePointCrossover(const GAGenome& a, const GAGenome& b, GAGenome* c, GAGenome* d) { return GA1DArrayGenome::OnePointCrossover(a,b,c,d); } inline int GAStringTwoPointCrossover(const GAGenome& a, const GAGenome& b, GAGenome* c, GAGenome* d) { return GA1DArrayGenome::TwoPointCrossover(a,b,c,d); } inline int GAStringPartialMatchCrossover(const GAGenome& a, const GAGenome& b, GAGenome* c, GAGenome* d) { return GA1DArrayGenome::PartialMatchCrossover(a,b,c,d); } inline int GAStringOrderCrossover(const GAGenome& a, const GAGenome& b, GAGenome* c, GAGenome* d) { return GA1DArrayGenome::OrderCrossover(a,b,c,d); } inline int GAStringCycleCrossover(const GAGenome& a, const GAGenome& b, GAGenome* c, GAGenome* d) { return GA1DArrayGenome::CycleCrossover(a,b,c,d); } #endif galib247/ga/GATree.C0100644003643600364360000002506110573535473013250 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- treetmpl.C mbwall 25feb95 Copyright 1995 Massachusetts Institute of Technology DESCRIPTION: This defines the templatized tree objects. TO DO: Make insert work better with size and depth so not so many recalcs needed. Implement better memory mangement, faster allocation, referencing. Use array representation of nodes so we don't have to do so much recursion. Figure better way to do traversals so that we speed up the swaps. ---------------------------------------------------------------------------- */ #ifndef _ga_treetmpl_C_ #define _ga_treetmpl_C_ #include extern GANodeBASE * _GATreeTraverse(unsigned int, unsigned int&, GANodeBASE *); //template void _GATreeDestroy(GANode *); //template GANode * _GATreeCopy(GANode *, GANode *); /* ---------------------------------------------------------------------------- Tree ---------------------------------------------------------------------------- */ // The destructor just goes through the tree and deletes every node. As with // any method that uses the BASE tree, we have to use its members so it doesn't // get messed up. template GATree::~GATree() { _GATreeDestroy(DYN_CAST(GANode*, rt)); iter.node = (GANodeBASE *)0; } // Yes, this is really ugly. We do a complete destruction of the existing tree // then we copy the new one. No caching, no nothing. Oh well. The iterator // is set to the root node - it should be set to the corresponding node, but // I won't do that for now. THIS IS A BUG! template void GATree::copy(const GATree & orig) { _GATreeDestroy(DYN_CAST(GANode*, rt)); rt = _GATreeCopy(DYN_CAST(GANode*, orig.rt), (GANode *)0); iter.node = rt; sz=orig.sz; csz=orig.csz; dpth=orig.dpth; cdpth=orig.cdpth; } // This remove method returns a tree with the removed node as its root. The // node we remove is the current node. We allocate memory for the tree, but // we don't allocate any memory for the node or its children. That is taken // from the previous (this) tree and it no longer has to worry about it. It // is the responsibility of the new tree to delete that memory. // The iterator gets set to the elder child of the node that was removed. If // there is no elder child, then it gets set to the parent. If no parent, then // it gets set to NULL. // Thank you to Uli Bubenheimer (uli@aisun1.ai.uga.edu) for the bug fix here. // I forgot to fix the pointers in the root node of the sub-tree. template GATree * GATree::remove() { GATree * t = new GATree; GANode * node = DYN_CAST(GANode*, iter.node); if(!node) return t; if(node->prev != node) iter.eldest(); else if(node->parent) iter.parent(); else iter.node = (GANodeBASE *)0; GANode * tmpnode = DYN_CAST(GANode*, GATreeBASE::remove(node)); tmpnode->prev = tmpnode; tmpnode->next = tmpnode; tmpnode->parent = (GANodeBASE *)0; t->insert(tmpnode, (GANode *)0, GATreeBASE::ROOT); return t; } // Recursively duplicate a subtree given a base node. This uses the _copy // method (which does a deep and wide copy). Here we just copy a node, then // sic the _copy method on the child if it exists. The parent of the new node // is set to NULL - this makes it a root node in the new tree object. // We do the cloning based on the valued passed to the routine. 0 is the // root node and makes a clone of the entire tree. This routine has no effect // on the iterator in the original tree. // The iterator in the clone is left pointing to the root node of the clone. template GATree * GATree::clone(unsigned int i) const { GATree * t = new GATree; GANode * node; unsigned int w=0; if(i == 0) node = DYN_CAST(GANode*, rt); else node = DYN_CAST(GANode*, _GATreeTraverse(i, w, rt)); if(!node) return t; GANode * newnode = new GANode(node->contents); newnode->child = _GATreeCopy(DYN_CAST(GANode*, node->child), newnode); if(newnode->child) newnode->child->parent = newnode; t->insert(newnode, (GANode *)0, GATreeBASE::ROOT); return t; } // Destroy the specified node and all nodes attached to it looking downward. // This does NOT destroy any nodes above the specified node. If this node is // in a tree, it will be removed before the nuking occurs. This gives the tree // object a chance to flag for any recalculations it might need. The destroy // method effect on the tree as a remove, but it is destructive (it frees up // the memory as well). // We do the nuking recursively, so its not really that efficient. I'll // figure out a better way to track these nodes one of these days. // We use the _destroy routine to do the recursion. _destroy kills all of // the siblings of the node whereas this routine kills only descendents. // This uses the current node as the one to destroy, so be sure to use the // iteration methods to move to the node you want to destroy. Once the node is // gone, we set the current node to the eldest child or parent of the node that // was destroyed. template int GATree::destroy() { GANodeBASE * node = iter.node; if(!node) return GATreeBASE::NO_ERR; if(node->prev == node || !node->prev) if(node->parent) iter.node = node->parent; else iter.node = (GANodeBASE *)0; else iter.eldest(); _GATreeDestroy(DYN_CAST(GANode*, node->child)); delete GATreeBASE::remove(node); return GATreeBASE::NO_ERR; } // Swap two subtrees. We use the nodes pointed to by the iterators in the // current tree and the one that was passed to us. The TreeBASE swaptree // changes the next, prev, parent, child pointers on the nodes we pass it as // well as the nodes that those nodes point to. // Notice that this routine uses the current location of the iterators to // do its job, so be sure to set them properly before you call this routine! // The iterators are reset to the nodes where the swaps occurred. Sizes and // depths are possibly changed - the insert method flags them for a recalc. // If an iterator is NULL then we do an insert ONLY if the root node of that // iterator's tree is NULL. If the tree's root is non-NULL, we don't do // anything (most likely the iterator was unset or badly set). template int GATree::swaptree(GATree * t) { GANodeBASE * tmp; if(t->iter.node && iter.node){ if(GATreeBASE::swaptree(t->iter.node, iter.node) == GATreeBASE::ERR) return GATreeBASE::ERR; if(t->rt == t->iter.node) t->rt = iter.node; tmp = t->iter.node; t->iter.node = iter.node; iter.node = tmp; t->csz = 1; t->cdpth = 1; // remember to flag the changes in t! csz = 1; cdpth = 1; } else if(t->iter.node){ // iter.node is NULL, so we have no root if(!rt){ // should always be true at this point tmp = t->GATreeBASE::remove(t->iter.node); // tmp->next = tmp; // tmp->prev = tmp; t->iter.node = (GANodeBASE *)0; if(insert(DYN_CAST(GANode*, tmp), (GANode *)0, GATreeBASE::ROOT) == GATreeBASE::ERR) return GATreeBASE::ERR; } } else if(iter.node){ // t's iter is NULL, so it has no root if(!t->rt){ // should always be true tmp = GATreeBASE::remove(iter.node); // tmp->next = tmp; // tmp->prev = tmp; iter.node = (GANodeBASE *)0; if(t->insert(DYN_CAST(GANode*,tmp),(GANode*)0,GATreeBASE::ROOT) == GATreeBASE::ERR) return GATreeBASE::ERR; } } // else both t->iter.node and iter.node are NULL, so don't do anything return GATreeBASE::NO_ERR; } // Same as the swaptree above, but this routine uses the node indices to do // the swap. This can be dangerous: if one of the nodes is a decendent of the // other then we could end up with a fragmented tree, so we'll have to check // for that situation. Unfortunately this check slows things down quite a bit. // If one is the ancestor of the other, then we don't do the swap. // This routine does not affect the size of the tree, but it could change the // depth of the tree. We leave the iterator where it was pointing before the // swap. template int GATree::swaptree(unsigned int a, unsigned int b) { unsigned int aw=0, bw=0; GANodeBASE * anode = _GATreeTraverse(a, aw, rt); GANodeBASE * bnode = _GATreeTraverse(b, bw, rt); return GATreeBASE::swaptree(anode,bnode); } // Swap two nodes in a tree, leave their subtrees intact. This routine does // not affect the iterator or the size or depth of the tree. template int GATree::swap(unsigned int a, unsigned int b) { unsigned int aw=0, bw=0; GANodeBASE * anode = _GATreeTraverse(a, aw, rt); GANodeBASE * bnode = _GATreeTraverse(b, bw, rt); return GATreeBASE::swapnode(anode,bnode); } /* ---------------------------------------------------------------------------- Recursive routines for the Tree objects ---------------------------------------------------------------------------- */ // Recursively copy a node, including all of its siblings. This routine copies // a row, then it calls itself to copy the next generation if it finds a next // generation in the next node. template GANode * _GATreeCopy(GANode * node, GANode * parent) { if(!node) return (GANode *)0; GANode * newnode = new GANode(node->contents); newnode->parent = parent; newnode->child = _GATreeCopy(DYN_CAST(GANode*, node->child), newnode); GANode *lasttmp = newnode, *newtmp = (GANode *)0; GANode *tmp = DYN_CAST(GANode*, node->next); while(tmp && tmp != node){ newtmp = new GANode(tmp->contents); newtmp->parent = parent; newtmp->child = _GATreeCopy(DYN_CAST(GANode*, tmp->child), newtmp); newtmp->prev = lasttmp; lasttmp->next = newtmp; lasttmp = newtmp; tmp = DYN_CAST(GANode*, tmp->next); } if(newtmp){ newtmp->next = newnode; newnode->prev = newtmp; } else{ newnode->next = newnode; newnode->prev = newnode; } return newnode; } // This routine destroys the specified node, its children, its siblings, and // all of their children, their childrens' siblings, etc. Since we kill off // all of the siblings, we need to set the parent's link to its child to NULL. template void _GATreeDestroy(GANode * node) { if(!node) return; if(node->parent) node->parent->child = (GANodeBASE *)0; _GATreeDestroy(DYN_CAST(GANode*, node->child)); GANodeBASE * tmp; while(node->next && node->next != node){ tmp = node->next; node->next = tmp->next; tmp->next->prev = node; _GATreeDestroy(DYN_CAST(GANode*, tmp->child)); delete tmp; } delete node; } #endif galib247/ga/GATree.h0100644003643600364360000002231010573535474013310 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- treetmpl.h mbwall 25feb95 Copyright 1995 Massachusetts Institute of Technology DESCRIPTION: This defines the templatized tree objects. ---------------------------------------------------------------------------- */ #ifndef _ga_treetmpl_h_ #define _ga_treetmpl_h_ #include #include /* ---------------------------------------------------------------------------- GATree ------------------------------------------------------------------------------- This object is a container for nodes that have a tree structure. The base tree object is responsible for maintaining the tree heirarchy. This object is responsible for doing the memory management (allocating and de-allocating the nodes in the tree). We insulate the user entirely from nodes - when you use a tree, you don't get nodes back, you get the contents of nodes (ie the user doesn't have to think about the tree parts of a node, they can simply assume that their data is organized into a tree structure). We include an iterator in this object so that you can navigate through the tree. You can create another iterator and assign it to your tree so you can have multiple iterators. All of the actions take place relative to the current location of the embedded iterator. None of the iterators change the state of the tree. Be careful so that you don't end up with an iterator dangling with a pointer to a part of a tree that no longer exists (I would need some kind of reference counting and/or message passing to take care of this at a lower level, and I'm not ready to implement that at this point). For now we allocate nodes on the fly. Eventually I would like to do some better memory management (arrays perhaps?) so we don't have to do so much alloc and dealloc and recursion. We depend on the template-ized GATreeIter routine, thus the declaration. copy Make a copy of the specified tree. Iterator goes to root node (should go to appropriate node in copy, but we don't do that yet). clone Allocate space and make a copy of the tree and return a pointer to the new one. The iterator of the original is not affected. The iterator of the clone is set to the appropriate place in the clone. If you specify a node index when you call clone then a clone of the subtree is made and the iterator in the clone is set to the root node (the top of the subtree). remove Remove the current node (and its subtree) from the tree and stick it into a new tree. Returns a pointer to the new tree. Leaves the original iterator pointing to the eldest child or parent of the node that was removed. Iter of the new tree points to the root node. destroy Destroys the node and subtree where the iterator is currently pointing. Moves the iterator to the eldest sibling or parent of the node that was deleted from the tree. swap Swap nodes in a tree, leaves the nodes' subtrees in place (subtrees do not move with the nodes in the swap). swaptree - tree Swap subtrees referenced by the iterators of this and the second tree. The iterators are reset to point to the new subtrees (same point in the trees, but different nodes due to the swap). swaptree - indices Swap the subtrees referenced by the integer values. Indices must not be related (ie one cannot be ancestor of the other). Iterator is not changed. insert - tree Inserts the contents of tree in to the current tree and removes it from the original tree. Does NOT delete the original tree, but DOES assume responsibility for the memory used by original tree contents. insert - object Inserts the object into a new node relative to the location of the iterator root, current, next, prev, parent, child, warp These iterator methods are defined as access to the embedded iterator of the tree. Use these methods to move the insertion point and to traverse the tree. You can also create other iterators for this tree, but they won't affect the contents. ---------------------------------------------------------------------------- */ template class GATreeIter; template class GATree : public GATreeBASE { public: GATree() : GATreeBASE() { iter(*this); } GATree(const T & t) : GATreeBASE(new GANode(t)), iter(*this) {} GATree(const GATree & orig){iter(*this); copy(orig);} GATree & operator=(const GATree & orig) {if(&orig != this) copy(orig); return *this;} virtual ~GATree(); GATree * clone(unsigned int i=0) const; // methods that modify the state of the tree void copy(const GATree & orig); int destroy(); int swaptree(GATree * t); int swaptree(unsigned int, unsigned int); int swap(unsigned int, unsigned int); GATree * remove(); int insert(GATree * t, GATreeBASE::Location where=GATreeBASE::BELOW){ if(this == t){ GAErr(GA_LOC, "GATree", "insert", gaErrCannotInsertIntoSelf); return GATreeBASE::ERR; } if(GATreeBASE::insert(t->rt, iter.node, where) == GATreeBASE::ERR){ return GATreeBASE::ERR; } iter.node = (t->rt ? t->rt : iter.node); t->rt=(GANodeBASE *)0; t->iter.node=(GANodeBASE *)0; return GATreeBASE::NO_ERR; } int insert(const T & t, GATreeBASE::Location where=GATreeBASE::BELOW){ GANode * c = new GANode(t); if(GATreeBASE::insert(c, iter.node, where) == GATreeBASE::ERR){ delete c; return GATreeBASE::ERR; } iter.node = c; return GATreeBASE::NO_ERR; } // typesafes on iteration methods. These call the built-in iterator then // return the contents of the now-current node. They do not affect the state // of the tree. T * root(){return iter.root();} T * current(){return iter.current();} T * next(){return iter.next();} T * prev(){return iter.prev();} T * parent(){return iter.parent();} T * child(){return iter.child();} T * eldest(){return iter.eldest();} T * youngest(){return iter.youngest();} T * warp(unsigned int i){return iter.warp(i);} T * warp(const GATreeIter & i) {return((i.tree == this) ? iter.warp(i) : (T *)0);} int nchildren(){return iter.nchildren();} int nsiblings(){return iter.nsiblings();} protected: int insert(GANode *n, GANode *idx, GATreeBASE::Location where=GATreeBASE::BELOW){ if(GATreeBASE::insert(n, idx, where) == GATreeBASE::ERR) return GATreeBASE::ERR; iter.node = n; return GATreeBASE::NO_ERR; } GATreeIter iter; friend class GATreeIter; }; /* ---------------------------------------------------------------------------- GATreeIter ------------------------------------------------------------------------------- This is a type-safe derivation of the base TreeIter object. I copied the methods from the base class (I know, a no-no) rather than doing calls to the base class methods. We depend on the template-ized GATree, thus the declaration. Behaviour for the iterator methods is defined as follows. If the current node is null, attempts to access a derived position from the current position will return NULL. The only way to reset the current node is to call the root() locater (you always have to start at the tree root to navigate the tree). If the current node is non-null and the derived node is null, the current node is NOT changed, but NULL is returned. When we create a new tree iterator, it defaults to the same node as the one used to create it. If it is created with a tree as its argument, it defaults to the tree's iterator's current position. ---------------------------------------------------------------------------- */ template class GATree; template class GATreeIter : public GATreeIterBASE { public: GATreeIter() : GATreeIterBASE(){} GATreeIter(const GATree & t) : GATreeIterBASE(t){node=t.iter.node;} GATreeIter(const GATreeIter & i) : GATreeIterBASE(i){} T * current() {return(node ? &((GANode *)node)->contents : (T *)0);} T * root() {return(((node=GATreeIterBASE::root()) != (GANodeBASE *)0) ? &((GANode *)GATreeIterBASE::root(node))->contents : (T *)0);} T * next() {return((node && node->next) ? &((GANode *)(node=node->next))->contents : (T *)0);} T * prev() {return((node && node->prev) ? &((GANode *)(node=node->prev))->contents : (T *)0);} T * parent() {return((node && node->parent) ? &((GANode *)(node=node->parent))->contents : (T *)0);} T * child() {return((node && node->child) ? &((GANode *)(node=node->child))->contents : (T *)0);} T * eldest() {return(node ? &((GANode *)GATreeIterBASE::eldest(node))->contents : (T *)0);} T * youngest() {return(node ? &((GANode *)GATreeIterBASE::youngest(node))->contents : (T *)0);} T * warp(const GATree & t){ tree = &t; node = t.iter.node; return(t.iter.node ? &((GANode *)(node=t.iter.node))->contents :(T *)0); } T * warp(const GATreeIter & i){ tree = i.tree; node = i.node; return(i.node ? &((GANode *)(node=i.node))->contents : (T *)0); } T * warp(unsigned int i){ GANodeBASE * n = GATreeIterBASE::warp(i); return(n ? &((GANode *)(node=n))->contents : (T *)0); } private: friend class GATree; }; #ifdef GALIB_USE_BORLAND_INST #include #endif #endif galib247/ga/GATreeBASE.C0100644003643600364360000005231210573535473013702 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- treebase.C mbwall 25nov94 Copyright 1995 Massachusetts Institute of Technology DESCRIPTION: This defines the tree objects. TO DO: Make insert work better with size and depth so not so many recalcs needed. Implement better memory mangement, faster allocation, referencing. Use array representation of nodes so we don't have to do so much recursion. Figure better way to do traversals so that we speed up the swaps. ---------------------------------------------------------------------------- */ #include #include static int _GATreeSize(GANodeBASE *); static int _GATreeDepth(GANodeBASE *); GANodeBASE * _GATreeTraverse(unsigned int, unsigned int &, GANodeBASE *); int _GATreeCompare(GANodeBASE * anode, GANodeBASE * bnode); // Traverse up the tree until we find the root node. If the node we got was // NULL, return NULL. Otherwise return the pointer to the root node. inline GANodeBASE * _GARootOfNode(GANodeBASE * n){ GANodeBASE * tmp = (GANodeBASE *)0; if((tmp=n) != (GANodeBASE *)0){while(tmp->parent) tmp = tmp->parent;} return tmp; } /* ---------------------------------------------------------------------------- TreeBASE ---------------------------------------------------------------------------- */ // Insert node n into the tree relative to node idx. There are four different // insertion modes: root, before, after, and below. If there is no root node, // then the node n becomes the root no matter what. If there is no root then // we don't do anything. // If the node that you are inserting has any siblings then the siblings will // be lost! Therefore we post an error message and return without doing // anything. // If you try to replace the existing root node, the previous root node // becomes the eldest child of the node that is being inserted. // root: idx is ignored. Beware that the previous root ptr is lost (unless // you keep you own copy of it somewhere else). // before: If node idx is the first in a row in the tree, then n becomes // the first in the row. If idx is the root node, then we post an error // message (can't have more than one root node). // after: If the node idx is the last in a row, n becomes the last node. If // idx is the root node, we post an error. // below: This is the default operation. This is the only valid operation // on a root node. int GATreeBASE::insert(GANodeBASE * n, GANodeBASE * idx, Location where) { if(!n) return NO_ERR; if(!idx){ if(!rt) where = ROOT; else if(where != ROOT){ GAErr(GA_LOC, "GATreeBASE", "insert", gaErrCannotInsertOnNilNode); return ERR; } } switch(where){ case ROOT: if((n->prev && n->prev != n) || (n->next && n->next != n)){ GAErr(GA_LOC, "GATreeBASE", "insert", gaErrCannotInsertWithSiblings); return ERR; } if(rt){ // root exists, so make old root eldest child rt->parent = n; if(n->child){ if(n->child->prev && n->child->prev != n->child){ rt->prev = n->child->prev; rt->next = n->child; n->child->prev->next = rt; n->child->prev = rt; } else{ rt->next = n->child; rt->prev = n->child->prev; n->child->prev = rt; n->child->next = rt; } } n->child = rt; } rt = n; n->parent = (GANodeBASE *)0; n->prev = n; n->next = n; break; case BEFORE: if(!idx->parent){ GAErr(GA_LOC, "GATreeBASE", "insert", gaErrCannotInsertBeforeRoot); return ERR; } n->parent = idx->parent; n->next = idx; n->prev = idx->prev; idx->prev->next = n; idx->prev = n; if(idx->parent && idx->parent->child == idx) n->parent->child = n; break; case AFTER: if(!idx->parent){ GAErr(GA_LOC, "GATreeBASE", "insert", gaErrCannotInsertAfterRoot); return ERR; } n->parent = idx->parent; n->prev = idx; n->next = idx->next; idx->next->prev = n; idx->next = n; break; case BELOW: n->parent = idx; if(idx->child){ n->prev = idx->child->prev; n->next = idx->child; idx->child->prev->next = n; idx->child->prev = n; } else{ n->prev = n; n->next = n; idx->child = n; } break; default: GAErr(GA_LOC, "GATreeBASE", "insert", gaErrBadWhereIndicator); break; } csz = 1; cdpth = 1; return NO_ERR; } // Remove the specified node from the tree. We don't cruise through the tree // to make certain that the node is in the tree. But we do check to make sure // that the connections were ok before we prune the node. If there is any // problem with the links, we return a NULL. If we get a NULL node, then we // don't do anything. // We don't do anything to the next, prev, etc links of the node that is // being removed (they are left pointing to where they used to point) so be // careful!! // If the removal is on the root node, set the root node to NULL. GANodeBASE * GATreeBASE::remove(GANodeBASE * n) { if(!n) return (GANodeBASE *)0; if(!n->next || !n->prev || n->prev->next != n || n->next->prev != n){ GAErr(GA_LOC, "GATreeBASE", "remove", gaErrBadTreeLinks); return (GANodeBASE*)0; } if(n->next == n || !n->next){ if(n->parent && n->parent->child == n) n->parent->child = (GANodeBASE *)0; } else{ if(n->parent && n->parent->child == n) n->parent->child = n->next; n->prev->next = n->next; n->next->prev = n->prev; } if(n == rt) rt = (GANodeBASE *)0; // uncomment these to modify the node that is getting removed n->prev = n; n->next = n; n->parent = 0; csz = 1; cdpth = 1; return n; } // Swap the specified nodes. If we get NULL nodes or the nodes are the same, // don't do anything. Swapping will work only on nodes that are not directly // related, eg a cannot be the ancestor of b. If you do a swap on nodes that // are directly related, you'll end up with two separate trees. For now we // don't check for this. // This swaps two nodes and their entire subtrees, its doesn't simply swap // the nodes themselves!! // We have to be concerned about the type of node that we get. If the node // is pointing to itself in its prev and next members, then it is probably a // root node. At any rate, we have to make the node its getting swapped with // have the same attributes (but not the same next and prev). // If either of the nodes is NULL, we don't do anything. // We check to see if the nodes are in the same tree (but only if we have to) // If the nodes are in the same tree then we check their ancestry before we // do the swap (so that we don't end up with any dangling trees or leaked // memory). // If the nodes are in the same tree and one of them is the root node, then // the other must have been a descendent of the first, so trying to swap them // is an error. If they are in different trees and one is the root node of // this tree, we can reset the root node of this tree. We have no way of // resetting the root node of the other tree, however, so beware that you // could lose the second tree (the one that used to be in this tree) if you // swap into another root. // This implementation has much room for improvement. We don't have to // traverse the tree multiple times, for example. int GATreeBASE::swaptree(GANodeBASE * a, GANodeBASE * b) { if(!a || !b || a == b) return NO_ERR; GANodeBASE * aprev = a->prev; GANodeBASE * anext = a->next; GANodeBASE * aparent = a->parent; GANodeBASE * bprev = b->prev; GANodeBASE * bnext = b->next; GANodeBASE * bparent = b->parent; if(anext == b || bnext == a){ // a & b are adjacent if(aparent && aparent->child == a) aparent->child = b; else if(bparent && bparent->child == b) bparent->child = a; if(anext == b && bnext != a){ // same as b->prev = a a->prev = b; a->next = bnext; b->prev = aprev; b->next = a; aprev->next = b; bnext->prev = a; } else if(bnext == a && anext != b){ // same as a->prev = b a->prev = bprev; a->next = b; b->prev = a; b->next = anext; anext->prev = b; bprev->next = a; } if(rt == a) rt = b; else if(rt == b) rt = a; } else{ // check for same tree then ancestry GANodeBASE * aroot = _GARootOfNode(a); GANodeBASE * broot = _GARootOfNode(b); if(aroot == broot){ // check ancestry while(aparent && aparent != b) aparent = aparent->parent; if(aparent == b){ GAErr(GA_LOC, "GATreeBASE", "swaptree", gaErrCannotSwapAncestors); return ERR; } while(bparent && bparent != a) bparent = bparent->parent; if(bparent == a){ GAErr(GA_LOC, "GATreeBASE", "swaptree", gaErrCannotSwapAncestors); return ERR; } aparent = a->parent; // reset the values bparent = b->parent; } // if not in same tree, we don't bother to check the ancestry if(aparent == bparent){ if(aparent && aparent->child == a) aparent->child = b; else if(bparent && bparent->child == b) bparent->child = a; } else{ if(aparent && aparent->child == a) aparent->child = b; if(bparent && bparent->child == b) bparent->child = a; } a->parent = bparent; b->parent = aparent; if(bprev == b || bnext == b){ a->prev = a; a->next = a; } else{ a->prev = bprev; a->next = bnext; bprev->next = a; bnext->prev = a; } if(aprev == a || anext == a){ b->prev = b; b->next = b; } else{ b->prev = aprev; b->next = anext; aprev->next = b; anext->prev = b; } if(aroot != broot){ if(rt == a) rt = b; else if(rt == b) rt = a; // We could lose the other node here, but we have no way of knowing what the // root node in the other tree is, so its up to the caller of this routine // to take care of this! } } csz = 1; cdpth = 1; return NO_ERR; } // Swap the specified nodes. If we get NULL nodes or the nodes are the same, // don't do anything. This moves the two nodes and leaves their subtrees in // place (if they have any). The subtrees do not move with the nodes. Note // that swapping two nodes shouldn't change the size or depth of the tree, so // we don't set the change flags. // We have to look for a few special cases. If a and b are parent/child or // a and b are adjacent then we have to give them special treatment. We don't // care if they are otherwise related. // We don't check for bogus configurations (eg b is a's child and a's next) // or for NULL members. We assume the tree is correctly configured. // We assume that the nodes are both in the same tree. If they are not, you // may (or may not) get an error. The error will occur if either of the nodes // is a root node and the nodes are not in the same tree. // At this point this routine is used ONLY for node swapping within the same // tree, so I won't worry about the different trees case. int GATreeBASE::swapnode(GANodeBASE * a, GANodeBASE * b) { if(!a || !b || a == b) return NO_ERR; GANodeBASE * aprev = a->prev; GANodeBASE * anext = a->next; GANodeBASE * achild = a->child; GANodeBASE * aparent = a->parent; GANodeBASE * bprev = b->prev; GANodeBASE * bnext = b->next; GANodeBASE * bchild = b->child; GANodeBASE * bparent = b->parent; if(anext == b || bnext == a){ // a & b are adjacent if(aparent && aparent->child == a) aparent->child = b; else if(bparent && bparent->child == b) bparent->child = a; a->child = bchild; b->child = achild; if(achild){ achild->parent = b; for(GANodeBASE * n=achild->next; n && n != achild; n=n->next) n->parent = b; } if(bchild){ bchild->parent = a; for(GANodeBASE * n=bchild->next; n && n != bchild; n=n->next) n->parent = a; } if(anext == b && bnext != a){ // same as b->prev = a a->prev = b; a->next = bnext; b->prev = aprev; b->next = a; aprev->next = b; bnext->prev = a; } else if(bnext == a && anext != b){ // same as a->prev = b a->prev = bprev; a->next = b; b->prev = a; b->next = anext; anext->prev = b; bprev->next = a; } } else{ // a & b are not adjacent if(bprev == b || bnext == b){ a->prev = a; a->next = a; } else{ a->prev = bprev; a->next = bnext; bprev->next = a; bnext->prev = a; } if(aprev == a || anext == a){ b->prev = b; b->next = b; } else{ b->prev = aprev; b->next = anext; aprev->next = b; anext->prev = b; } if(achild == b){ // same as b->parent = a a->parent = b; a->child = bchild; b->parent = aparent; b->child = a; if(aparent && aparent->child == a) aparent->child = b; for(GANodeBASE * n=a->next; n && n != a; n=n->next) n->parent = b; if(bchild){ bchild->parent = a; for(GANodeBASE * n=bchild->next; n && n != bchild; n=n->next) n->parent = a; } } else if(bchild == a){ // same as a->parent = b a->parent = bparent; a->child = b; b->parent = a; b->child = achild; if(bparent && bparent->child == b) bparent->child = a; if(achild){ achild->parent = b; for(GANodeBASE * n=achild->next; n && n != achild; n=n->next) n->parent = b; } for(GANodeBASE * n=b->next; n && n != b; n=n->next) n->parent = a; } else{ // a and b are not adjacent nor parent-child a->parent = bparent; a->child = bchild; b->parent = aparent; b->child = achild; if(aparent == bparent){ if(aparent && aparent->child == a) aparent->child = b; else if(bparent && bparent->child == b) bparent->child = a; } else{ if(aparent && aparent->child == a) aparent->child = b; if(bparent && bparent->child == b) bparent->child = a; } if(achild){ achild->parent = b; for(GANodeBASE * n=achild->next; n && n != achild; n=n->next) n->parent = b; } if(bchild){ bchild->parent = a; for(GANodeBASE * n=bchild->next; n && n != bchild; n=n->next) n->parent = a; } } } if(rt == a) rt = b; // this only works if they're in the same tree! else if(rt == b) rt = a; return NO_ERR; } // Return the number of nodes in the tree. We do a complete traversal of the // tree and count the number of nodes that we encounter. Could do this breadth // first or depth first - doesn't really matter. We have to traverse the // entire tree to do the count. // We have to do a little work-around here to get through the const-ness of // the size method. Its ok to call size on a const object because it does not // modify the logical state of the object. It does, however, modify the // physical state of the object. So to work around the strictness of the // const specifier, we do a little pointer magic and cast this to be non-const. int GATreeBASE::size() const { if(!csz) return sz; GATreeBASE * This = CON_CAST(GATreeBASE *, this); This->csz = 0; return(This->sz = _GATreeSize(rt)); } // Return the number of levels in the tree. We do a complete traversal of the // tree and keep a count of the number of times we go down and come up a level. // I should be able to combine _size and _depth so we don't have to do two // traversals... int GATreeBASE::depth() const { if(!cdpth) return dpth; GATreeBASE * This = CON_CAST(GATreeBASE *, this); This->cdpth = 0; return(This->dpth = _GATreeDepth(rt)); } // Is node i an ancestor of node j or vice versa? If so, we return 1. Other- // wise we return a 0. int GATreeBASE::ancestral(unsigned int i, unsigned int j) const { GATreeIterBASE aiter(*this); GATreeIterBASE biter(*this); GANodeBASE * aparent, *a; GANodeBASE * bparent, *b; aparent = a = aiter.warp(i); bparent = b = biter.warp(j); while(aparent && aparent != b) aparent = aparent->parent; if(aparent == b) return 1; while(bparent && bparent != a) bparent = bparent->parent; if(bparent == a) return 1; return 0; } /* ---------------------------------------------------------------------------- Recursive routines for the TreeBASE objects ---------------------------------------------------------------------------- */ static int _GATreeSize(GANodeBASE * node) { if(!node) return 0; int count = 1 + _GATreeSize(node->child); for(GANodeBASE * tmp=node->next; tmp && tmp != node; tmp=tmp->next){ count++; count += _GATreeSize(tmp->child); } return count; } static int _GATreeDepth(GANodeBASE * node) { if(!node) return 0; int depth; int maxdepth = 1 + _GATreeDepth(node->child); for(GANodeBASE * tmp=node->next; tmp != node; tmp=tmp->next){ depth = 1 + _GATreeDepth(tmp->child); maxdepth = maxdepth > depth ? maxdepth : depth; } return maxdepth; } /* ---------------------------------------------------------------------------- TreeIterBASE ---------------------------------------------------------------------------- */ // Return the root of the specified node. GANodeBASE * GATreeIterBASE::root(GANodeBASE * c) { if(!c) return (GANodeBASE *)0; while(c->parent != (GANodeBASE *)0) c = c->parent; return(node = c); } // Return the eldest child in a row of siblings. The eldest is the one that // the parent of that row points to. // This could get into an infinite loop if the tree structure were ever // corrupted, so be sure that it doesn't! Also, it will break if the parent // member is not set in any child, so be sure that never happens either. // Remember to set the current node to the one we found. GANodeBASE * GATreeIterBASE::eldest(GANodeBASE * c) { if(!c) return (GANodeBASE *)0; if(!c->parent) return(node=c); GANodeBASE * tmp = c; while(tmp->parent->child != tmp) tmp = tmp->next; return(node = tmp); } // Return the youngest child in a row of siblings. The youngest is the last // one in the row (ie the prev for the eldest since we're using circular lists) // Basically we just find the eldest then take the one previous to that one. // Remember to set the current node to the one we found. GANodeBASE * GATreeIterBASE::youngest(GANodeBASE * c) { if(!c) return (GANodeBASE *)0; if(!c->parent) return(node=c); GANodeBASE * tmp = c; while(tmp->parent->child != tmp) tmp = tmp->next; return(node = tmp->prev); } // Return the number of siblings for the specified node. Notice that this // function returns the number of siblings INCLUDING the specified node. int GATreeIterBASE::nsiblings(GANodeBASE * c) { GANodeBASE * tmp = c; int n=1; while(tmp->next && ((tmp=tmp->next) != c)) n++; return n; } // Return the number of children for the specified node. This is basically the // same code as the nsiblings routine, but we look at the child of the node, // not the node itself. int GATreeIterBASE::nchildren(GANodeBASE * c) { if(!c->child) return 0; GANodeBASE * tmp = c->child; int n=1; while(tmp->next && ((tmp=tmp->next) != c->child)) n++; return n; } // Set the current node to the node indexed by the integer x. If x is out of // bounds, we return NULL and don't change the state of the iterator. This // method uses a depth-first traversal to find the node. Root node is 0, then // we go up from there. GANodeBASE * GATreeIterBASE::warp(unsigned int x) { unsigned int w=0; GANodeBASE * tmp = _GATreeTraverse(x, w, root()); if(tmp) node = tmp; return(tmp); } // Return the number of nodes in the tree from the specified node on down. // Similar to the TreeBASE size method, but we don't set the sz member and // we can't cache the size since this could be called on any node. int GATreeIterBASE::size(GANodeBASE * n) { return(_GATreeSize(n)); } // Return the depth of the tree from the specified node on down. int GATreeIterBASE::depth(GANodeBASE * n) { return(_GATreeDepth(n)); } // Traverse the tree (depth-first) until we come to the node with the index // specified by 'index'. Return NULL if cur != index. GANodeBASE * _GATreeTraverse(unsigned int index, unsigned int & cur, GANodeBASE * node) { if(!node) return (GANodeBASE *)0; if(cur == index) return node; cur++; GANodeBASE * n; if((n = _GATreeTraverse(index, cur, node->child)) != (GANodeBASE *)0) return n; for(GANodeBASE * tmp=node->next; tmp && tmp != node; tmp=tmp->next){ if(cur == index) return tmp; cur++; if((n = _GATreeTraverse(index, cur, tmp->child)) != (GANodeBASE *)0) return n; } return (GANodeBASE *)0; } // Comparison operators for a a tree check for identical tree structure // only (no check for same contents of nodes). These check for // similar tree structure - we traverse one tree and expect the second to be // just like it (depth-first traversal). If there is any difference along the // way, then we return a not equal. // Neither of these operators affects the internal iterator of either // tree genome in any way. // Recursively traverse two trees at the same time. Return 1 if they are // different, return a 0 if they are identical. This checks only the tree // structure, not the node contents. int _GATreeCompare(GANodeBASE * anode, GANodeBASE * bnode) { if(anode==0 && bnode==0) return 0; if(anode==0 || bnode==0) return 1; int count = _GATreeCompare(anode->child, bnode->child); for(GANodeBASE * atmp=anode->next, * btmp=bnode->next; atmp && atmp != anode; atmp=atmp->next, btmp=btmp->next){ count += _GATreeCompare(atmp->child, btmp->child); } return count; } galib247/ga/GATreeBASE.h0100644003643600364360000002245510573535473013754 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- treebase.h mbwall 25nov94 Copyright 1995 Massachusetts Institute of Technology DESCRIPTION: This defines the tree objects. ---------------------------------------------------------------------------- */ #ifndef _ga_treebase_h_ #define _ga_treebase_h_ #include /* ---------------------------------------------------------------------------- GATreeBASE ------------------------------------------------------------------------------- This is the base tree class from which template trees are derived. This object does no memory management - it just keeps track of a tree structure. Whoever calls the members of this object is responsible for allocating and deallocating the memory associated with each node. This class does not define any of the iteration operators for traversing the tree. That is left to the iterator friend of this class. We have to break through the const-ness of the tree in order to make things work properly. When you ask for the size of a tree, you don't change the size but you do (possibly) change the value of the sz member. This doesn't change the state of the tree, so it is, in effect, a const-correct operation. But const is too strict, so we have to work around it. See the size() definition to see how this is done. Beware that when you copy this object, you copy pointers, NOT the contents of the pointers. You cannot simply say tree1 = tree2 or GATreeBASE t = tree1. If you do, you'll get a copy of the tree object but not a copy of the tree (the copy will point to the same tree as the original). creation Create a tree by passing a root node. If you don't pass a root node, then the next node assigned to the tree with an insert or append operation will become the root node (regardless of the idx node you pass). insert Stick a node into the tree. Where the node goes depends on the second node and the value of the flag. There are three flag values: before, after, and below. The flag specifies where the new node should go relative to the old node. If oldnode is the root node, the only valid value for flag is below. If there are already children on a node, specifying below puts the new node at the end of the row of children (it becomes the youngest sibling). If you don't pass a value for flag, it defaults to below. The syntax for using the insert method looks like this: mytree.insert(newnode, oldnode, GATreeBASE::before); mytree.insert(newnode, oldnode); Insertions assume that the node to be inserted has NO siblings. If it does, they will be lost! However, the node MAY have children (a subtree). If the insert was successful, return NO_ERR. If there was a problem, return ERR. remove Remove the specified node from the tree. If the node does not exist, an ERR message is posted and NULL is returned. If the node has children, the children are removed from the tree as well (they stay with the node). A pointer to the node is returned if the removal is successful, otherwise NULL. swaptree Move node a to node b's position in the tree and vice versa. This swap maintains the integrity of all of a's and b's descendents. It checks for ancestry conflicts so that you cannot swap a node with one of its descendents. You can swap nodes in different trees, but if you do, be sure to check for root nodes! The swap routine can set only the root node of the current tree - it doesn't know about the root node of the other tree, so you'll have to reset that one. If the swap was successful, return NO_ERR. If there was a problem, return ERR. swapnode Switch nodes a and b, leaving their subtrees (if any) in their original positions (the subtrees don't follow a and b). If the swap was successful, return NO_ERR. If there was a problem, return ERR. size How many nodes are in the tree? We keep a flag to tell us if any operation has been performed that would require a recalculation of the size. If you change the contents of the tree using any method other than those in this object (which you could do, by the way) then you risk screwing up the count. depth How many levels (generations) are there in the tree? ---------------------------------------------------------------------------- */ class GATreeBASE { public: enum Location {ROOT=0, BEFORE, AFTER, BELOW}; // values for 'where' to insert enum {NO_ERR = 0, ERR = -1}; // returns codes for tree funcs GATreeBASE(){rt=(GANodeBASE *)0; sz=0; dpth=0; csz=0; cdpth=0;} GATreeBASE(GANodeBASE * n){rt=n; csz=1; cdpth=1;} GANodeBASE * remove(GANodeBASE * n); int insert(GANodeBASE * n, GANodeBASE * idx, Location where=BELOW); int swaptree(GANodeBASE * a, GANodeBASE * b); int swapnode(GANodeBASE * a, GANodeBASE * b); int size() const; int depth() const; int ancestral(unsigned int i, unsigned int j) const; protected: int sz, dpth; // number of nodes, number of levels in tree short csz, cdpth; // have the contents changed since last update? GANodeBASE *rt; // the root node of the tree private: GATreeBASE(const GATreeBASE &){} // we don't allow copying GATreeBASE & operator=(const GATreeBASE &){return *this;} // or op= friend class GATreeIterBASE; }; /* ---------------------------------------------------------------------------- GATreeIterBASE ------------------------------------------------------------------------------- This is the base class for iterators for the tree objects. We define this class separately from the Tree object so that you can have multiple interators for each tree and so that you can more easily customize the traversal algorithms within the iterator. From the object point of view, the way you traverse a tree is independent of how you represent the tree. Like the TreeBASE object, this object doesn't do any memory allocation or deallocation. All we do is provide tree traversal. Notice that we keep a 'current location' in the tree - whatever your last query was is stored as the node, so if you refer to the current member, you'll get your last query. If you pass a NULL node to these routines they will break. In the interest of speed we don't do any error checking. creation Create an iterator by passing either a tree or another iterator. If you pass a tree, the iterator will default to the root node of the tree. If you pass another iterator, the new iterator will point to the same node that the original iterator points to. nchildren Returns the number of children that are direct offspring of the specified node (or current node if none is specified). nsiblings Returns the number of nodes at the same level as the specified or current node. This number includes the specified or current node. current, root, next, prev, parent, child, eldest, youngest, warp Set the iterator to the specified node and return a pointer to the node that the iterator now points to. If current is NULL or a NULL is passed to one of these routines, a NULL is returned the iterator does not move. warp Move the iterator to the node referenced by index. The root node is node '0' then the count increases from there using a depth-first search. This means that any subtree in a tree will have a contiguous chunk of indices. ---------------------------------------------------------------------------- */ class GATreeIterBASE { public: GATreeIterBASE(){node=(GANodeBASE *)0; tree=(GATreeBASE *)0;} GATreeIterBASE(const GATreeBASE & t){tree = &t; node = t.rt;} GATreeIterBASE(const GATreeIterBASE & i){tree = i.tree; node = i.node;} void operator()(const GATreeBASE & t){tree = &t; node = t.rt;} GANodeBASE * current(GANodeBASE * c) {return(c ? (node=c) : (GANodeBASE *)0);} GANodeBASE * current(){return node;} GANodeBASE * next(){return(node ? (node=node->next) : (GANodeBASE *)0);} GANodeBASE * next(GANodeBASE * c) {return(c ? (node=c->next) : (GANodeBASE *)0);} GANodeBASE * prev(){return(node ? (node=node->prev) : (GANodeBASE *)0);} GANodeBASE * prev(GANodeBASE * c) {return(c ? (node=c->prev) : (GANodeBASE *)0);} GANodeBASE * parent() {return(node ? (node=node->parent) : (GANodeBASE *)0);} GANodeBASE * parent(GANodeBASE * c) {return(c ? (node=c->parent) : (GANodeBASE *)0);} GANodeBASE * child(){return(node ? (node=node->child) : (GANodeBASE *)0);} GANodeBASE * child(GANodeBASE * c) {return(c ? (node=c->child) : (GANodeBASE *)0);} GANodeBASE * root(){return(tree ? (node=tree->rt) : (GANodeBASE *)0);} GANodeBASE * root(GANodeBASE * c); GANodeBASE * eldest() {return(node ? (node=eldest(node)) : (GANodeBASE *)0);} GANodeBASE * eldest(GANodeBASE * c); GANodeBASE * youngest() {return(node ? (node=youngest(node)) : (GANodeBASE *)0);} GANodeBASE * youngest(GANodeBASE * c); GANodeBASE * warp(unsigned int); GANodeBASE * warp(const GATreeIterBASE & i){ tree=i.tree; node=(GANodeBASE *)0; return(i.node ? (node=i.node) : (GANodeBASE *)0); } int size(){return(node ? size(node) : 0);} int size(GANodeBASE * c); int depth(){return(node ? depth(node) : 0);} int depth(GANodeBASE * c); int nchildren(){return(node ? nchildren(node) : 0);} int nchildren(GANodeBASE * c); int nsiblings(){return(node ? nsiblings(node) : 0);} int nsiblings(GANodeBASE * c); protected: GANodeBASE * node; const GATreeBASE * tree; }; #endif galib247/ga/GATreeGenome.C0100644003643600364360000002312710573535474014405 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- tree.C mbwall 25feb95 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved DESCRIPTION: Source file for the tree genome. ---------------------------------------------------------------------------- */ #ifndef _ga_tree_C_ #define _ga_tree_C_ #include #include #include #include extern int _GATreeCompare(GANodeBASE * anode, GANodeBASE * bnode); template const char * GATreeGenome::className() const {return "GATreeGenome";} template int GATreeGenome::classID() const {return GAID::TreeGenome;} template GATreeGenome::GATreeGenome(GAGenome::Evaluator f, void * u) : GATree(), GAGenome(DEFAULT_TREE_INITIALIZER, DEFAULT_TREE_MUTATOR, DEFAULT_TREE_COMPARATOR) { evaluator(f); userData(u); crossover(DEFAULT_TREE_CROSSOVER); } template GATreeGenome::GATreeGenome(const GATreeGenome & orig) : GATree(), GAGenome() { GATreeGenome::copy(orig); } template GATreeGenome::~GATreeGenome() { } template GAGenome * GATreeGenome::clone(GAGenome::CloneMethod flag) const { GATreeGenome *cpy = new GATreeGenome(); if(flag == (int)CONTENTS){cpy->copy(*this);} // cast is for metrowerks... else{cpy->GAGenome::copy(*this);} return cpy; } template void GATreeGenome::copy(const GAGenome & orig) { if(&orig == this) return; const GATreeGenome* c = DYN_CAST(const GATreeGenome*, &orig); if(c) { GAGenome::copy(*c); GATree::copy(*c); } } #ifdef GALIB_USE_STREAMS // Traverse the tree (breadth-first) and dump the contents as best we can to // the stream. We don't try to write the contents of the nodes - we simply // write a . for each node in the tree. // We allocate space for x,y coord pair for each node in the tree. Then we // do a depth-first traversal of the tree and assign coords to the nodes in the // order we get them in the traversal. Each coord pair is measured relative to // the parent of the node. template void _tt(STD_OSTREAM & os, GANode * n) { if(!n) return; GANodeBASE * node = DYN_CAST(GANodeBASE*, n); os.width(10); os << node << " "; os.width(10); os << node->parent << " "; os.width(10); os << node->child << " "; os.width(10); os << node->next << " "; os.width(10); os << node->prev << " "; os.width(10); os << &(n->contents) << "\n"; _tt(os, DYN_CAST(GANode*, node->child)); for(GANodeBASE * tmp=node->next; tmp && tmp != node; tmp=tmp->next){ os.width(10); os << tmp << " "; os.width(10); os << tmp->parent << " "; os.width(10); os << tmp->child << " "; os.width(10); os << tmp->next << " "; os.width(10); os << tmp->prev << " "; os.width(10); os << &(DYN_CAST(GANode*, tmp)->contents) << "\n"; _tt(os, DYN_CAST(GANode*, tmp->child)); } } template int GATreeGenome::write(STD_OSTREAM & os) const { os << "node parent child next prev contents\n"; _tt(os, (GANode *)(this->rt)); return 0; } #endif template int GATreeGenome::equal(const GAGenome & c) const { if(this == &c) return 1; const GATreeGenome& b = DYN_CAST(const GATreeGenome&, c); return _GATreeCompare(this->rt, b.rt) ? 0 : 1; } /* ---------------------------------------------------------------------------- Operator definitions ---------------------------------------------------------------------------- */ // This mutation method is destructive. We randomly pick a node in the tree // then delete the subtree and node at that point. Each node in the tree has // a pmut probability of getting nuked. // After the mutation the iterator is left at the root of the tree. template int GATreeGenome::DestructiveMutator(GAGenome & c, float pmut) { GATreeGenome &child=DYN_CAST(GATreeGenome &, c); register int n, i; if(pmut <= 0.0) return 0; n = child.size(); float nMut = pmut * STA_CAST(float,n); if(nMut < 1.0){ // we have to do a flip test for each node nMut = 0; for(i=0; i int GATreeGenome::SwapNodeMutator(GAGenome & c, float pmut) { GATreeGenome &child=DYN_CAST(GATreeGenome &, c); register int n, i; if(pmut <= 0.0) return 0; n = child.size(); float nMut = pmut * STA_CAST(float,n); nMut *= 0.5; // swapping one node swaps another as well if(nMut < 1.0){ // we have to do a flip test for each node nMut = 0; for(i=0; i int GATreeGenome::SwapSubtreeMutator(GAGenome & c, float pmut) { GATreeGenome &child=DYN_CAST(GATreeGenome &, c); register int n, i; int a, b; if(pmut <= 0.0) return 0; n = child.size(); float nMut = pmut * STA_CAST(float,n); nMut *= 0.5; // swapping one node swaps another as well if(nMut < 1.0){ // we have to do a flip test for each node nMut = 0; for(i=0; i float GATreeGenome::TopologyComparator(const GAGenome& a, const GAGenome& b) { if(&a == &b) return 0; const GATreeGenome& sis=DYN_CAST(const GATreeGenome&, a); const GATreeGenome& bro=DYN_CAST(const GATreeGenome&, b); return STA_CAST(float, _GATreeCompare(sis.rt, bro.rt)); } // The default crossover operator takes a node from parent a (with its entire // sub-tree) and replaces it with a node from parent b (with its entire sub- // tree). If the crossover site is not set, then we pick a random site based // on the trees in the genomes we're going to cross. Once we have a valid // crossover site, we copy the trees from the two genomes. // If the crossover site is out of bounds (ie refers to a node not in the // tree) then we don't do anything to the child. // We allow crossover at ANY site in the genomes (including at the root // node). // *** we should be able to speed this up. there is an extra traversal when we // do the check to see if the crossover site is valid. template int GATreeGenome:: OnePointCrossover(const GAGenome& p1, const GAGenome& p2, GAGenome* c1, GAGenome* c2){ const GATreeGenome &mom=DYN_CAST(const GATreeGenome &, p1); const GATreeGenome &dad=DYN_CAST(const GATreeGenome &, p2); int nc=0; unsigned int a = GARandomInt(0, mom.size()-1); unsigned int b = GARandomInt(0, dad.size()-1); GATreeIter momiter(mom), daditer(dad); GATree * tree; if(c1 && c2){ GATreeGenome &sis=DYN_CAST(GATreeGenome &, *c1); GATreeGenome &bro=DYN_CAST(GATreeGenome &, *c2); // first do the sister... if(momiter.warp(a) && daditer.warp(b)){ sis.GATree::copy(mom); tree = dad.GATree::clone(b); sis.warp(a); sis.swaptree(tree); delete tree; sis.warp(0); } // ...now do the brother. if(momiter.warp(a) && daditer.warp(b)){ bro.GATree::copy(dad); tree = mom.GATree::clone(a); bro.warp(b); bro.swaptree(tree); delete tree; bro.warp(0); } nc = 2; } else if(c1){ GATreeGenome &sis=DYN_CAST(GATreeGenome &, *c1); if(GARandomBit()){ if(momiter.warp(a) && daditer.warp(b)){ sis.GATree::copy(mom); tree = dad.GATree::clone(b); sis.warp(a); sis.swaptree(tree); delete tree; sis.warp(0); } } else{ if(momiter.warp(a) && daditer.warp(b)){ sis.GATree::copy(dad); tree = mom.GATree::clone(a); sis.warp(b); sis.swaptree(tree); delete tree; sis.warp(0); } } nc = 1; } return nc; } #endif galib247/ga/GATreeGenome.h0100644003643600364360000000540310573535473014446 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- tree.h mbwall 25feb95 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved DESCRIPTION: This header defines the interface for the tree genome. ---------------------------------------------------------------------------- */ #ifndef _ga_tree_h_ #define _ga_tree_h_ #include #include /* ---------------------------------------------------------------------------- TreeGenome ------------------------------------------------------------------------------- Beware that the tree genome can grow unbounded - there is no size limit on the tree, so if you have an objective function that encourages size the tree will grow until you run out of memory. ---------------------------------------------------------------------------- */ template class GATreeGenome : public GATree, public GAGenome { public: GADeclareIdentity(); static int DestructiveMutator(GAGenome &, float); static int SwapNodeMutator(GAGenome &, float); static int SwapSubtreeMutator(GAGenome &, float); static int OnePointCrossover(const GAGenome&, const GAGenome&, GAGenome*, GAGenome*); static float TopologyComparator(const GAGenome&, const GAGenome&); // static float NodeComparator(const GAGenome&, const GAGenome&); public: GATreeGenome(GAGenome::Evaluator f=NULL, void * u=NULL); GATreeGenome(const GATreeGenome &); GATreeGenome & operator=(const GAGenome & orig) {copy(orig); return *this;} virtual ~GATreeGenome(); virtual GAGenome *clone(GAGenome::CloneMethod flag=CONTENTS) const; virtual void copy(const GAGenome &); #ifdef GALIB_USE_STREAMS virtual int write (STD_OSTREAM &) const; #endif virtual int equal(const GAGenome & c) const; // Here we do inlined versions of the access members of the super class. We // do our own here so that we can set/unset the _evaluated flag appropriately. int destroy() { _evaluated = gaFalse; return GATree::destroy(); } int swaptree(GATree * t) { _evaluated = gaFalse; return GATree::swaptree(t); } int swaptree(unsigned int i, unsigned int j) { _evaluated = gaFalse; return GATree::swaptree(i,j); } int swap(unsigned int i, unsigned int j) { _evaluated = gaFalse; return GATree::swap(i,j); } GATree * remove() { _evaluated = gaFalse; return GATree::remove(); } int insert(GATree * t, GATreeBASE::Location where=GATreeBASE::BELOW) { _evaluated = gaFalse; return GATree::insert(t, where); } int insert(const T & t, GATreeBASE::Location where=GATreeBASE::BELOW) { _evaluated = gaFalse; return GATree::insert(t, where); } }; #ifdef GALIB_USE_BORLAND_INST #include #endif #endif galib247/ga/gatypes.h0100644003643600364360000000155710573535474013667 0ustar mwallmwall// $Header$ /* ---------------------------------------------------------------------------- gatypes.h mbwall 29apr95 Copyright (c) 1995 Massachusetts Institute of Technology all rights reserved ---------------------------------------------------------------------------- */ #ifndef _ga_types_h_ #define _ga_types_h_ typedef float GAProbability; typedef float GAProb; // This enforces return values and arguments to functions that want strict // boolean arguments. typedef enum _GABoolean { gaFalse=0, gaTrue } GABoolean, GABool; typedef enum _GAStatus { gaSuccess=0, gaFailure=-1 } GAStatus; // This defines what type to use for the bitstream data storage. Use the // smallest type available on your platform. typedef unsigned char GABit; #define GAMax(a,b) ((a) > (b) ? (a) : (b)) #define GAMin(a,b) ((a) < (b) ? (a) : (b)) #endif galib247/ga/gaversion.h0100644003643600364360000000124710573536001014167 0ustar mwallmwall/* ---------------------------------------------------------------------------- version.h mbwall 10oct98 This is the header file to keep track of the versions and revisions of the GA library. You can use the ident command to extract the version and other build information from the galib object file. ---------------------------------------------------------------------------- */ #ifndef _ga_version_h_ #define _ga_version_h_ #include #define GALIB_LIBRARY_IDENTIFIER \ "$Date: 2004-12-29 11:24:43 -0500 (Wed, 29 Dec 2004) $"\ "$Revision: 43 $"\ "$Configuration: " GALIB_OS "-" GALIB_CPU "-" GALIB_COMPILER " $" const char* GAConfig(); #endif galib247/ga/makefile0100644003643600364360000000156610573535473013541 0ustar mwallmwall# -*- Mode: makefile -*- # Copyright (c) 1994-1996 Massachusetts Institute of Technology # Copyright (c) 1996-2005 Matthew Wall # ----------------------------------------------------------------------------- include ../makevars include makefile.sources INC_DIRS= -I.. .SUFFIXES: .C .C.o: $(CXX) $(CXXFLAGS) $(INC_DIRS) -c $< $(LIB): $(OBJS) $(PRELINK) $(AR) $(LIB) $? $(RANLIB) $(LIB) echo "$(CXX) $(CXXFLAGS)" > BUILD @echo $(LIB) is now up-to-date .C.a:; clean: $(RM) $(LIB) BUILD $(RM) *.o *~ .#* *.bak core ii_files ptrepository install:: $(LIB) $(INSTALL) $(LIB) $(LIB_DEST_DIR) $(RM) $(HDR_DEST_DIR)/ga; $(MKDIR) $(HDR_DEST_DIR)/ga $(CP) $(HDRS) $(TMPL_SRCS) ../VERSION BUILD $(HDR_DEST_DIR)/ga uninstall: $(RM) $(LIB_DEST_DIR)/$(LIB) $(RM) $(HDR_DEST_DIR)/ga depend: $(MKDEPEND) $(INC_DIRS) $(SRCS) # DO NOT DELETE THIS LINE -- make depend depends on it. galib247/ga/makefile.bcc0100644003643600364360000000234210573535473014260 0ustar mwallmwall# -*- Mode: makefile -*- # Copyright (c) 1994-1996 Massachusetts Institute of Technology # Copyright (c) 1996-2005 Matthew Wall # ----------------------------------------------------------------------------- !include ../makevars.bcc !include makefile.sources CXXFLAGS = $(CXXFLAGS) -I.. STATIC = $(LIB_NAME) LIB = $(STATIC).lib all: $(LIB) # this really sucks, but i have not yet found documentation about the borland # make or link that will let me avoid the for loop. $(LIB): $(OBJS) @for %i in ( $(OBJS) ) do \ $(AR) $(ARFLAGS) $(LIB) +%i @echo $(LIB_NAME) is now up-to-date install: install.lib install.hdr @echo installation complete install.lib: $(LIB) lib_directories $(INSTALL) $(LIB) $(LIB_DEST_DIR) install.hdr: hdr_directories @for %i in ( $(HDRS) ) do \ $(CP) /Q %i $(HDR_DEST_DIR)\$(LIB_NAME) @for %i in ( $(TMPL_SRCS) ) do \ $(CP) /Q %i $(HDR_DEST_DIR)\$(LIB_NAME) lib_directories: @if not exist $(LIB_DEST_DIR) \ $(MKDIR) $(LIB_DEST_DIR) hdr_directories: @if not exist $(HDR_DEST_DIR)\$(LIB_NAME) \ $(MKDIR) $(HDR_DEST_DIR)\$(LIB_NAME) remove: $(RM) $(LIB_DEST_DIR)\$(LIB) $(RM) $(HDR_DEST_DIR)\$(LIB_NAME) clean: $(RM) *.obj *.o *.tds $(RM) $(LIB_NAME).lib galib247/ga/makefile.sources0100644003643600364360000000316510573535474015221 0ustar mwallmwall# -*- Mode: makefile -*- HDRS= ga.h gaconfig.h gatypes.h gaid.h garandom.h gaerror.h std_stream.h \ GAEvalData.h GAParameter.h GAStatistics.h \ GABaseGA.h GASStateGA.h GASimpleGA.h GAIncGA.h GADemeGA.h GADCrowdingGA.h \ GASelector.h GAScaling.h GAPopulation.h GAGenome.h GAMask.h \ GABinStr.h gabincvt.h GAAllele.h GAArray.h GANode.h \ GA1DBinStrGenome.h GA2DBinStrGenome.h GA3DBinStrGenome.h GABin2DecGenome.h \ GA1DArrayGenome.h GA2DArrayGenome.h GA3DArrayGenome.h \ GAStringGenome.h GARealGenome.h \ GATreeBASE.h GATree.h GATreeGenome.h GAListBASE.h GAList.h GAListGenome.h SRCS= garandom.C gaerror.C GAParameter.C GAStatistics.C \ GABaseGA.C GASStateGA.C GASimpleGA.C GAIncGA.C GADemeGA.C GADCrowdingGA.C \ GASelector.C GAScaling.C GAPopulation.C GAGenome.C \ GABinStr.C gabincvt.C GAAllele.C GAStringGenome.C GARealGenome.C \ GA1DBinStrGenome.C GA2DBinStrGenome.C GA3DBinStrGenome.C GABin2DecGenome.C \ GA1DArrayGenome.C GA2DArrayGenome.C GA3DArrayGenome.C \ GATreeBASE.C GATree.C GATreeGenome.C GAListBASE.C GAList.C GAListGenome.C OBJS= garandom.o gaerror.o GAParameter.o GAStatistics.o \ GABaseGA.o GASStateGA.o GASimpleGA.o GAIncGA.o GADemeGA.o GADCrowdingGA.o \ GASelector.o GAScaling.o GAPopulation.o GAGenome.o \ GABinStr.o gabincvt.o GAAllele.o \ GA1DBinStrGenome.o GA2DBinStrGenome.o GA3DBinStrGenome.o GABin2DecGenome.o \ GA1DArrayGenome.o GA2DArrayGenome.o GA3DArrayGenome.o \ GATreeBASE.o GATree.o GATreeGenome.o GAListBASE.o GAList.o GAListGenome.o TMPL_SRCS= GAAllele.C \ GA1DArrayGenome.C GA2DArrayGenome.C GA3DArrayGenome.C \ GATree.C GATreeGenome.C GAList.C GAListGenome.C \ GAStringGenome.C GARealGenome.C galib247/ga/makefile.vcpp0100644003643600364360000000210410573535474014476 0ustar mwallmwall# -*- Mode: makefile -*- # Copyright (c) 1994-1996 Massachusetts Institute of Technology # Copyright (c) 1996-2005 Matthew Wall # ----------------------------------------------------------------------------- !include ../makevars.vcpp !include makefile.sources CXXFLAGS = $(CXXFLAGS) /I.. STATIC = $(LIB_NAME) LIB = $(STATIC).lib all: $(LIB) $(LIB): $(OBJS) $(AR) $(ARFLAGS) /out:$(LIB) $? @echo $(LIB_NAME) is now up-to-date install: install.lib install.hdr @echo installation complete install.lib: $(LIB) lib_directories $(INSTALL) $(LIB) $(LIB_DEST_DIR) install.hdr: hdr_directories @for %i in ( $(HDRS) ) do \ $(CP) /Q %i $(HDR_DEST_DIR)\$(LIB_NAME) @for %i in ( $(TMPL_SRCS) ) do \ $(CP) /Q %i $(HDR_DEST_DIR)\$(LIB_NAME) lib_directories: @if not exist $(LIB_DEST_DIR) \ $(MKDIR) $(LIB_DEST_DIR) hdr_directories: @if not exist $(HDR_DEST_DIR)\$(LIB_NAME) \ $(MKDIR) $(HDR_DEST_DIR)\$(LIB_NAME) remove: $(RM) $(LIB_DEST_DIR)\$(LIB) $(RM) $(HDR_DEST_DIR)\$(LIB_NAME) clean: $(RM) *.obj *.o *.pdb vc* $(RM) $(LIB_NAME).lib galib247/ga/std_stream.h0100644003643600364360000000242010573535473014345 0ustar mwallmwall// $Header$ // Copyright (c) 2005 Matthew Wall, all rights reserved // ---------------------------------------------------------------------------- #ifndef _ga_std_stream_h_ #define _ga_std_stream_h_ #include #if defined(GALIB_USE_STREAMS) #if defined(GALIB_USE_ANSI_HEADERS) #include #include #else #include #include #endif #if defined(GALIB_USE_STD_NAMESPACE) #define STD_ISTREAM std::istream #define STD_OSTREAM std::ostream #define STD_IFSTREAM std::ifstream #define STD_OFSTREAM std::ofstream #define STD_IOS_IN std::ios::in #define STD_IOS_OUT std::ios::out #define STD_IOS_TRUNC std::ios::trunc #define STD_IOS_APP std::ios::app #define STD_IOS_BADBIT std::ios::badbit #define STD_ENDL std::endl #define STD_COUT std::cout #define STD_CERR std::cerr #else #define STD_ISTREAM istream #define STD_OSTREAM ostream #define STD_IFSTREAM ifstream #define STD_OFSTREAM ofstream #define STD_IOS_IN ios::in #define STD_IOS_OUT ios::out #define STD_IOS_TRUNC ios::trunc #define STD_IOS_APP ios::app #define STD_IOS_BADBIT ios::badbit #define STD_ENDL endl #define STD_COUT cout #define STD_CERR cerr #endif #endif #endif galib247/LICENSE0100644003643600364360000000253310573535500012441 0ustar mwallmwallProviding credit where credit is due ------------------------------------------------------------------------------- GAlib is available under a BSD-style license found in the COPYRIGHT file. You can use GAlib for any purpose, and you can distribute GAlib subject to the terms in the license. If you distribute GAlib, you must include the contents of the COPYRIGHT file in your distribution. If you use GAlib in a commercial product, you should provide credit as follows (typically in the 'about box'): This product includes GAlib, a library of genetic algorithm components. Copyright Massachusetts Institute of Technology and Matthew Wall. To refer to GAlib from a research publication, you should provide credit as follows: This research was performed using GAlib, a library of genetic algorithm components (http://lancet.mit.edu/ga/). The GNU portions of the GAlib distribution ------------------------------------------------------------------------------- The portions of GAlib that contain code from the GNU g++ library are covered under the terms of the GNU Public License. As such they are freely available and do not fall under the terms of the GAlib licensing. The portions of GAlib that are based upon GNU code are all in the 'gnu' directory in the examples directory (in GAlib release 2.3.2 and later). galib247/makefile0100644003643600364360000000235610573535501013140 0ustar mwallmwall# -*- Mode: makefile -*- # Makefile for GAlib # Copyright (c) 1996-2005 Matthew Wall, all rights reserved # # If you need to customize the build of galib, you should first modify the # variables in the makevars file. GALIB_VERSION=2.4.7 GALIB_VER=247 TMPDIR=/var/tmp RELDIR=$(TMPDIR)/galib$(GALIB_VER) all: lib ex lib: cd ga; $(MAKE) ex: cd examples; $(MAKE) test: lib ex cd examples; $(MAKE) test install: cd ga; $(MAKE) install uninstall: cd ga; $(MAKE) uninstall clean: cd ga; $(MAKE) clean cd examples; $(MAKE) clean release: clean rm -rf $(RELDIR) mkdir -p $(RELDIR) cp -rp * $(RELDIR) rm -rf `find $(RELDIR) -name CVS` rm -rf `find $(RELDIR) -name .svn` rm -f `find $(RELDIR) -name "*~"` echo $(GALIB_VERSION) > $(RELDIR)/VERSION perl -pi -e 's/evision: \d+\.\d+ /evision: $(GALIB_VERSION) /' $(RELDIR)/ga/gaversion.h perl -pi -e 'chop($$dt=`date +"%Y/%m/%d %H:%M:%S"`); s/Date: ..\/..\/.. ..:..:.. /Date: $$dt /' $(RELDIR)/ga/gaversion.h cd $(RELDIR)/..; tar cvfz galib$(GALIB_VER).tgz galib$(GALIB_VER) > $(TMPDIR)/galib$(GALIB_VER)-manifest-tar.txt cd $(RELDIR)/..; zip -r galib$(GALIB_VER).zip galib$(GALIB_VER) > $(TMPDIR)/galib$(GALIB_VER)-manifest-zip.txt @echo " GAlib $(GALIB_VERSION) has been released to $(TMPDIR)" galib247/makefile.bcc0100644003643600364360000000066610573535501013670 0ustar mwallmwall# -*- Mode: makefile -*- # Makefile to build GAlib with Borland tools # Copyright (c) 1996-2005 Matthew Wall, all rights reserved all: lib ex lib: cd ga make -f makefile.bcc cd .. ex: cd examples make -f makefile.bcc cd .. test: cd examples make -f makefile.bcc test cd .. clean: cd ga make -f makefile.bcc clean cd .. cd examples make -f makefile.bcc clean cd .. install: cd ga make -f makefile.bcc install cd .. galib247/makefile.vcpp0100644003643600364360000000076410573535501014110 0ustar mwallmwall# -*- Mode: makefile -*- # Makefile to build GAlib with Microsoft tools # Copyright (c) 1996-2005 Matthew Wall, all rights reserved all: lib ex lib: cd ga nmake /nologo /f makefile.vcpp cd .. ex: cd examples nmake /nologo /f makefile.vcpp cd .. test: cd examples nmake /nologo /f makefile.vcpp test cd .. clean: cd ga nmake /nologo /f makefile.vcpp clean cd .. cd examples nmake /nologo /f makefile.vcpp clean cd .. install: cd ga nmake /nologo /f makefile.vcpp install cd .. galib247/makevars0100644003643600364360000000603110573535734013176 0ustar mwallmwall# -*- Mode: makefile -*- # Copyright (c) 2005 Matthew Wall, all rights reserved # makefile variables for compiling on unix environments # ----------------------------------------------------------------------------- LIB =libga.a ### Set these directories to whatever is appropriate for your system. These ### are used only if you do a 'make install'. They specify where the library ### and header files should be installed. DESTDIR=/usr/local HDR_DEST_DIR=$(DESTDIR)/include LIB_DEST_DIR=$(DESTDIR)/lib ### Make sure that these are ok for your operating system. MKDEPEND = makedepend MKDIR = mkdir -p CP = cp RM = rm -rf ### Uncomment a block from the list below appropriate for the compiler and ### operating system on which you are compiling. # gcc3, gcc4 # verified 28dec04 on linux-x86 (fedora core 2 with gcc 3.3.3) # verified 28dec04 on linux-ppc (yellow dog 3 with gcc 3.2.2) # verified 28dec04 on win2k-x86 (cygwin-win2k with gcc 3.3.3) # verified 10jan05 on linux-x86 (fedora core 3 with gcc 3.4.2) # verified 06mar07 on linux-x86 (debian with gcc 3.3.5) # verified 06mar07 on linux-x86 (ubuntu with gcc 4.0.3) # verified 06mar07 on macosx-ppc (macosx 10.4.8 with gcc 4.0.1) CXX = g++ CXXFLAGS = -g -Wall LD = g++ -w AR = ar rv INSTALL = install -c RANLIB = echo no ranlib # gcc2 # verified 28dec04 on linux-x86 (redhat 6.2 with gcc 2.95.2) # verified 28dec04 on sol7-x86 (solaris 7 with gcc 2.95.2) # verified 28dec04 on sol6-sparc (solaris 6 with gcc 2.95.2) #CXX = g++ #CXXFLAGS = -g -Wall -O -fexceptions -O0 #LD = g++ -w #AR = ar rv #INSTALL = install -c #RANLIB = echo no ranlib # macosx using gcc2 # verified 28dec04 macosx-ppc (macosx 10.3.7 with gcc 2.95.2) #CXX = gcc2 #CXXFLAGS = -g -Wall -fexceptions #LD = gcc2 -w #AR = ar rv #INSTALL = install #RANLIB = ranlib #CXX_LIBS = -lstdc++ # macosx using gcc3 # verified 28dec04 macosx-ppc (macosx 10.3.7 with gcc 3.3) #CXX = g++ #CXXFLAGS = -g -Wall -O -O0 #LD = gcc3 -w #AR = ar rv #INSTALL = install #RANLIB = ranlib # HPUX11 with aCC # verified 28dec04 hpux11-hppa (hpux 11 with aCC A.03.31) #CXX = aCC #CXXFLAGS = -g #LD = aCC #AR = ar rv #INSTALL = bsdinst -c #RANLIB = ranlib # AIX 4.3 with xlC # verified 28dec04 aix-ppc (aix 4.3.3 with xlC 6.0.0.5) #CXX = xlC #CXXFLAGS = -g -O -qrtti=all #LD = xlC #AR = ar rv #INSTALL = bsdinst -c #RANLIB = ranlib # IRIX 6.x with new 32-bit libraries # verified 28dec04 irix65-mips (irix 6.5 with CC 7.3.1.2m) #CXX = CC #CXXFLAGS = -g -fullwarn -n32 #LD = ld #AR = ar rv #INSTALL = bsdinst -c #RANLIB = echo no ranlib # IRIX 6.x with old 32-bit libraries # verified 28dec04 irix65-mips (irix 6.5 with CC 7.3.1.2m) #CXX = CC #CXXFLAGS = -g -fullwarn #LD = ld #AR = ar rv #INSTALL = bsdinst -c #RANLIB = echo no ranlib galib247/makevars.bcc0100644003643600364360000000170610573535500013717 0ustar mwallmwall# -*- Mode: makefile -*- # Copyright (c) 1999 Matthew Wall, all rights reserved # makefile variables for compiling on windows # ----------------------------------------------------------------------------- LIB_NAME= ga ### Set these directories to whatever is appropriate for your system. These ### used only if you do a 'make install'. They specify where the library and ### header files should be installed. DESTDIR=c:\temp HDR_DEST_DIR=$(DESTDIR)\include LIB_DEST_DIR=$(DESTDIR)\lib MKDEPEND = echo MKDIR = mkdir CP = xcopy RM = del /f CXX = bcc32.exe LD = ilink32.exe AR = tlib.exe INSTALL = copy CXX_INC_DIR = c:\Borland\BCC55\Include CXX_LIB_DIR = c:\Borland\BCC55\Lib CFLAGS = CXXFLAGS = -q -P -RT -I$(CXX_INC_DIR) -w-var -w-inl LDFLAGS = -q -c -x -Gn -L$(CXX_LIB_DIR) ARFLAGS = .SUFFIXES: .SUFFIXES: .C .C.o: $(CXX) $(CXXFLAGS) -o$*.o -c $< .C.obj: $(CXX) $(CXXFLAGS) -o$*.obj -c $< galib247/makevars.vcpp0100644003643600364360000000405710573535500014142 0ustar mwallmwall# -*- Mode: makefile -*- # Copyright (c) 1999-2005 Matthew Wall, all rights reserved # makefile variables for compiling on windows # ----------------------------------------------------------------------------- LIB_NAME= ga ### Set these directories to whatever is appropriate for your system. These ### used only if you do a 'make install'. They specify where the library and ### header files should be installed. DESTDIR=c:\temp HDR_DEST_DIR=$(DESTDIR)\include LIB_DEST_DIR=$(DESTDIR)\lib MKDEPEND = echo MKDIR = mkdir CP = xcopy RM = del /f CXX = cl.exe LD = link.exe AR = lib.exe INSTALL = copy # Here is a quick summary of the switches that cause much grief. These are # for the microsoft visual c++ compilers. # # switch thread dll/exe library # /MD multi DLL MSCVRT.LIB # /ML single EXE LIBC.LIB # /MT multi EXE LIBCMT.LIB # # /GR enable RTTI # /GX enable synchronous exception handling # /YX automate precompiled header # /FD generate file dependencies CFLAGS = /nologo /D_WINDOWS /DWIN32 /D_MBCS /W3 /GR /GX /TP LFLAGS = /nologo /subsystem:console /incremental:no !ifdef RELEASE_BUILD CXXDLLFLAGS = $(CFLAGS) /DNDEBUG /MD /O2 CXXLIBFLAGS = $(CFLAGS) /DNDEBUG /MT /O2 CXXEXEFLAGS = $(CFLAGS) /DNDEBUG /MT /O2 LINKFLAGS = $(LFLAGS) !else CXXDLLFLAGS = $(CFLAGS) /D_DEBUG /MDd /Od /Zi CXXLIBFLAGS = $(CFLAGS) /D_DEBUG /MTd /Od /Zi CXXEXEFLAGS = $(CFLAGS) /D_DEBUG /MTd /Od /Zi LINKFLAGS = $(LFLAGS) /debug !endif !ifdef SHARED_BUILD !ifdef LIBRARY_BUILD CXXFLAGS = $(CXXDLLFLAGS) /DCOMPILE_GALIB_AS_DLL /D_USRDLL LINKFLAGS = $(LINKFLAGS) /dll !else CXXFLAGS = $(CXXEXEFLAGS) /DUSE_GALIB_AS_DLL LINKFLAGS = $(LINKFLAGS) !endif !else !ifdef LIBRARY_BUILD CXXFLAGS = $(CXXLIBFLAGS) /DCOMPILE_GALIB_AS_LIB /D_LIB LINKFLAGS = $(LINKFLAGS) !else CXXFLAGS = $(CXXEXEFLAGS) /DUSE_GALIB_AS_LIB LINKFLAGS = $(LINKFLAGS) !endif !endif LDFLAGS = $(LINKFLAGS) ARFLAGS = /nologo .SUFFIXES: .SUFFIXES: .C .C.o: $(CXX) $(CXXFLAGS) /c $< /Fo$*.o galib247/README0100644003643600364360000000462210573535501012316 0ustar mwallmwallGAlib: A C++ Genetic Algorithm Library Copyright (c) 1994-1996 MIT, 1996-2005 Matthew Wall GAlib is a C++ library of genetic algorithm objects. With GAlib you can add evolutionary algorithm optimization to almost any program using any data representation and standard or custom selection, crossover, mutation, scaling, and termination methods. The library requires reasonable C++ compiler. I have tested GAlib on MacOS using Metrowerks and Symantec development environments, MacOSX using gcc2/3, DOS/Windows using Borland C++ and MS VC++, and various UNIX platforms using g++, egcs, CC, DCC, xlC, and aCC. Graphic examples (XWindows/Motif and MS Windows) are available, as are parallel, distributed implementations using PVM. There are about 30 examples that illustrate various ways to use GAlib on a variety of problems. WHERE TO GET IT --------------------------------------------------------------- http://lancet.mit.edu/ga ftp://lancet.mit.edu/pub/ga/ COMPILATION ------------------------------------------------------------------- There are two things to build: the library and the examples. Here is the short version of how to build and test everything: On unix, % make test On windows, with MS VC++, > nmake /f makefile.vcpp test On windows, with Borland, > make -f makefile.bcc test If that does not work, then here are the files you might have to modify: - ga/gaconfig.h - this contains the macros that control library options - makevars - compiler and linker options for each compilier/os - makefile - the actual build rules for putting everything together If you still have problems, look at Installation.html in the doc directory. DOCUMENTATION and MAILING LIST ------------------------------------------------ Complete documentation in html format is available in the doc directory. The distribution site contains PDF and PostScript(tm) versions. A current list of bugs is at http://lancet.mit.edu/ga/Bugs.html There are two GAlib mailing lists: galib@mit.edu and galib-announce@mit.edu The first list is an unmoderated list intended as a forum for galib users to help each other. The second is only for announcements about GAlib updates. To subscribe, send email to galib-request@mit.edu (or galib-announce-request) with the word 'subscribe' as the subject and nothing in the body of the email. To unsubscribe, send email with the word 'unsubscribe' as the subject. galib247/RELEASE-NOTES0100644003643600364360000005456210573535501013337 0ustar mwallmwallrelease notes for GAlib 2.4.6 January 2005 ------------------------------------------------------------------------------- Updated tspview and gaview graphic examples in the examples/graphic directory. These now build cleanly out-of-the-box on linux (and other) unix systems that have X windows. The options for building with MOTIF widget sets (still) work and are now the default. Try running tspview with two different genetic algorithms to see how differently they behave. For example: tspview ga 1 (generational) tspview ga 2 (crowding) tspview ga 3 (simple) will give you three different windows. Run them to see how generational, simple, and crowding algorithms differ. Note that the crowding algorithm will find all of the (equally good) optimal solutions. Updated macros in gaconfig.h to have fewer clashes with other libraries. Much improved out-of-the-box behavior with various recent compilers, including gcc3 and vcpp7. Added options for building on macosx with gcc2 and gcc3. The library is now up-to-date with respect to: gcc2, gcc3, vcpp6, vcpp7, xlC, aCC, CC, BCC55 (that is all the compilers I have with which to test). Split the windows makefiles into two, one for vcpp and one for borland. The make syntax is simply too incompatible to keep them in a single file (for now anyway, until I find a source for the arcane behaviors of each one). Still to come is complete makefile support for building shared libraries - sorry, but for now you have to do that on your own. All galib random number generators have been change to garan* in order to avoid naming conflicts with other libraries. There is still only one rng at a time and no run-time modification of the rng is possible (that is coming with 3.0). Better inclusion of GARealGenome and GAStringGenome files for specializations. the new method accommodates gcc3 premature instantiation quirks and makes the code that uses the genomes slightly less cryptic. See ex21.C to see how this is done. There is now a file called std_stream.h in the ga directory. this file takes care of the differences between various iostream naming requirements. Some platforms require std for the namespace, some do not. Some require use of , others require simply . When you create your own code that uses GAlib, you do not need to use the macros from std_stream.h, but they are used in the examples so that the example code will build in any environment, regardless of its use of streams. The macros for controlling use of streams are now easier to understand and use. Fixed bug in GASelector::update that could cause memory corruption (thanks to Giovanni Sartoni for finding this one). Added assertions to expose any other end-of-array problems in the selector algorithms. Use local copy of score when calculating population statistics just in case the genome scores change on each invocation of the score method. The seed can now be remembered by each genetic algorithm (or passed on the fly as before). Only the GABaseGA class remembers the seed - derived GA classes do nothing with it right now. This is so that existing behavior will not be changed. Then next major release will include persistance and use of seeds within the genetic algorithms. 2.4.5 February 2000 ------------------------------------------------------------------------------- Created a function GABin2DecPhenotype::equal(const GABin2DecPhenotype & b) since vcpp would not recognize operator== as a friend of the phenotype class. Removed inclusion of iostream.h from gaerror.C Created new projects using codewarrior 5.3 on macos. They are now included as a separate file for download from the ftp site. Removed USE_RTTI from gaconfig.h since it is not used (yet). Cleanup to the library makefiles. Separate makefiles for unix and winnt (no need to compile using vcpp projects anymore!) I decided not to use autoconf since the overhead of using autoconf outweighs the benefits (at least until someone makes it easier to use and modify). At this point i think it is easier for people to modify the makefile (or makevars) rather than to figure out how to use all the options to configure. Fixed GAGeneticAlgorithm::TerminateUponPopConvergence so that it now does the right thing. In doing so we redefined what population convergence means. Now it is: min/max. When minimizing, this will stop the evolution when the value is less that the threshhold. When maximizing, this will stop the evolution when the value is greather than the threshhold. The threshhold must be between 0 and 1, inclusive. Note that this method fails if the maximum objective score might be zero. (thanks to Bill White) Fixed initialization bug in GAPopulation.C that could cause unitialized memory read (thanks to Harold H Soleng of Norwegian Computing Center). Fixed boolean read problem in the GAParameters object (thanks to Klaus Kirchberg). Added compile-time warning message to garandom.h to help people avoid bogus random number generator issues. Fixed RNG bug in RAN1 and RAN2 (thanks to Peter Ross and George LeCompte). Fixed RNG bug in RAN3 (thanks to Peter Ross). Started putting the DLL code in, but that will have to wait until i have more time for extensive testing. Probably that will go in when the thread-safe mods go in. Cleaned up the HTML documentation in the distribution a little bit. Everything is now in CVS, including the web site. I am no longer maintaining a separate dos distribution. Changes in version 2.4.4 4 April 1999 ------------------------------------------------------------------------------- Fixes to gaconfig.h to make things compile out-of-the-box a bit better for more platforms. Replaced C-style casts with dynamic_cast and friends. Macros expand to the old-style casts if your compiler does not support the new-style casts. Fixed const-ness of genomes used internally to the built-in operators. Added minimal support for rtti. This will be disabled if your compiler does not support it. Added support for ansi streams. You can now select whether to use ansi streams or the older streams by defining the appropriate directive. GAlib will then use either the old streams headers , the ansi streams headers , or no streams at all. Changes from int to unsigned int for these functions: GABin2DecPhenotype::size GABin2DecPhenotype::nPhenotypes Many fixes to signed/unsigned conversions. For the most part, all I did was make them explicit using static_cast Added GADCrowdingGA to the library (it has been in the TSP example for a long time, now it is part of the library). Fixed questionable initialization of iterators in GATree and GAList The library now compiles more cleanly on vcpp, metrowerks, sgi CC, and g++ 2.8.1 (ok, i had to disable a couple of vcpp warnings, but of what use is a warning that says "you're losing data converting 1.0 into a float" ?) Can anyone tell me what to do about g++ warnings about "variable 'xxx' might be clobbered by 'longjmp' or 'vfork'" ? Graphic examples are now included in the windows distribution: points on a surface and travelling salesman. Really, they are this time :) They are hacked together using a windows wizard (gads, what a horrible environment that is), but they should get you started. Added #undef for min/max in GAPopulation.h and GABin2Dec.h (microsoft headers in particular are promiscuous in their definition of min/max macros) Changed doubles to floats in GAPopulation::scale GAPopulation::statistics Changed template instantiation syntax in GARealGenome.C and GAStringGenome.C Changes in version 2.4.3 11 November 1998 ------------------------------------------------------------------------------- Graphic examples for mac Graphic examples for windows Fixed example 13 to actually do what it claimed to do. Beware that it may run for a really long time now (it has a GA embedded in another GA, so each evaluation results in another GA run). Fixed gaversion.h to accurately record the library version (for better use with ident) Added definition of M_PI to the examples in which that macro is used (some platforms do not have M_PI defined in their math headers) Fixed bug in GAAlleleSet<>::allele() that caused upper/lower bounds to be generated when they should not have been. Note that your initialize, crossover, mutate operators must respect allele set limit boundaries otherwise you'll end up with bogus values. Fixed bugs in GADemeGA: GADemeGA::nMigration did not set parameter list GADemeGA::nPopulations did not set parameter list GADemeGA::step set numrep incorrectly GADemeGA::step looped on tmppop size rather than nrepl GADemeGA::nReplacement did not update tmppop size properly GADemeGA::nReplacement did not update the parameter list GADemeGA::nPopulations did not update nrepl or pstats correctly Fixed bug in GARealGaussianMutator that caused no mutation to occur in cases when 100% mutation should have happened. Fixed bug in GAGeneticAlgorithm::TerminateUponConvergence that would cause the evolution to stop immediately when doing a minimization with convergence as the stopping criterion. Fixed various memory leaks GAAlleleSetArray<>::remove Various makefile/project additions and cleanup New project files for Codewarrior New project files for MS VC++ Fixes to makefiles to make cross-unix compiles easier. Fixed html documentation: For the GAStatistics object, the member functions offlineMax, offlineMin, minEver, maxEver were incorrect. In GAPopulation::diversity, 1 indicates that each individual is completely different. The title of Melanie Mitchell's book had been omitted. Fixed mask clear bug in GA1DArrayGenome<>::CycleCrossover Fixed signed/unsigned problems in array genomes. As a result, the following member functions have been removed: GA1DArrayGenome<>::operator[] GA1DArrayGenome<>::operator[](int) Various fixes and features to random number generator Added chi-square tests to the randtest program for better RNG testing. Added GAGetRandomSeed to get the random seed from the library. Added GAGetRNG function to tell which RNG was compiled in. Fixed bug in implementation of GARandomSeed. Now the changing bits of the value returned by time() are correctly assimilated into the seed, even if the seed has fewer bits than the value returned by time(). Fixed bug in read member of 1D, 2D, and 3D binary string genomes. Added pragmas for VC++ in gaconfig.h to disable warnings. Fixed bug in resizeBehaviour routines in 3D genomes Fixed bug in example 5 and example 14 in which score cache flag was not properly updated. Changes in version 2.4.2 13 November 1996 ------------------------------------------------------------------------------- Sorry, but I lost the list due to a hard drive crash :( Changes in version 2.4.1 10 November 1996 ------------------------------------------------------------------------------- Project files are (finally) available for metrowerks and borland compilers. Others will appear as I get them. Fixed the constructors for 2D and 3D array allele genomes so that you can construct them with allele set arrays as well as allele sets. You must define your own initializer to take advantage of the allele set arrays, however (initialization using the default initializer will ignore the additional allele sets). Fixed a problem with ios::out and other stream flags in the statistics and parameters modules. If your compiler is ANSI standard and uses the STL streams then you may need to use the NO_STREAMS directive to turn off the streams in GAlib (GAlib is not yet STL-streams compliant). Added blend crossover (BLX) and arithmetic crossover for real number genomes. An implementation of the edge recombination crossover (ERX) for list genomes is included in two of the examples (for the travelling salesman problems). A new revision, Revision B, of the PostScript documentation. Fixed a problem in the statistics object that caused it to record the wrong scores when minimizing the objective. Fixed the scaling, statistics, and population objects to handle large objective scores properly (scores that are near FLT_MAX and/or FLT_MIN). Major cleanup of the MacOS and DOS/Windows versions of GAlib. Installation is an order of magnitude easier. Added a graphic travelling salesman example (graphic examples are only available for unix versions - Mac and PC versions will come as soon as I have the basic code to do graphic display and rudimentary GUI on those platforms). Fixed the simple genetic algorithm class to do elitism properly when minimizing. Added virtual destructors to the Node and NodeBASE classes so that derived node classes will work properly. Fixed the formating problems in the DOS/Windows package, including both the end-of-line characters and the GIF images. Changes in version 2.4 released 3 June 1996 ------------------------------------------------------------------------------- The base genetic algorithm class, 'GA', was renamed to 'GAGeneticAlgorithm' Function prototypes for genome operators are now defined in the genome scope. Similarly, function prototypes for genetic algorithm and population object operators are defined in their respective scopes. The 'score' member of the genome can now be used on const genomes. The documentation is now distributed with GAlib. The documentation now contains a page illustrating how to define your own operators and derive your own GAlib-based classes. GAlib now compiles warning-free when you use the -Wall flag for the g++ compiler. The number of warnings when compiled with Borland, Metrowerks, and Symantec compilers has also been reduced (although Borland still won't let you inline for, while, or switch statements). The config.h header file now figures out as much as possible about your system so that you should not have to tweak it nearly as much as in previous releases. GASUSSelector was renamed to GAUniformSelector The GASharing object has been reworked to better match the description of scaling proposed by Goldberg. It now lets you select both the sigma cutoff and alpha values for tuning the scaling radius and importance. The steady-state genetic algorithm will now work properly with the sharing method of fitness scaling (although Goldberg typically refers to sharing in the context of non-overlapping populations, you can use it with overlapping populations if you do the replacement right). GAlib works with PVM 3.3.10 or later. This release of GAlib includes examples that show how to use GAlib with PVM for two types of parallelization: (1) one genome per process/CPU and (2) one population per process/CPU. I'm also considering an MPI example (if only there were stable C++ bindings for PVM and MPI). Parallel populations on a single CPU are now possible using the island model with migration rates and (custom) replacement between populations. Each population can have its own selection and replacement methods, independent of the other populations. By default all populations are clones of each other (same initialization, mutation, crossover, selection, replacement). The parallel populations are evolved using steady-state genetic algorithm model with user-specified overlap, etc. This is illustrated in one of the examples. Default and built-in operators are now defined as static member function of the genome classes with which they are associated. This cleans up the namespace quite a bit. Template classes now have default operators whereever they can be defined - no more ARRAY_TYPE or LIST_TYPE. The genome files have been consolidated. Rather than a bunch of files (typically 6) for each genome, the library uses a single pair (.h and .C) for each genome. For example, binstr1.[ch|xs|op].[C|h] is now simply binstr1.[C|h]. Genomes now contain an 'evaluation data' object. This is a pointer to an object derived from the EvalData class. Its purpose is to provide a mechanism for storing custom information with each genome. The userData member is similar in function, but whereas the userData object is the same for all genomes, the evalData object may be different for each genome. (the evalData object supercedes the 'ObjectiveVector') The ArrayGenome class has been restructured as ArrayGenome and ArrayAlleleGenome (derived from ArrayGenome). The library includes instantiations of char and double versions of the ArrayAlleleGenome class to form the StringGenome and RealGenome classes. The RealGenome class provides a mechanism for doing an array of bounded real numbers and/or sets of real numbers. Sample uniform and gaussian mutator are included for the RealGenome class. A new compile-time flag, NO_STREAMS, has been added to let you compile-out the GAlib dependencies on the streams library. When you compile-out the streams dependencies you cannot use the default GAlib routines for reading from and writing to file, but the error routines will still work properly. Error handling has been improved a little sages to a GAlib-specific error handler. You can override the library's error handler to redirect (or ignore) the messages as you see fit. A converter architecture has been added to the binary string objects. GAlib contains two default converters: Gray and Binary encode/decode. You can use either of these or define your own for mapping decimal values into the binary strings. The binary-to-decimal conversions now support more bits - up to 128 (depending on the system you're running on). The statistics object has been cleaned up and more statistics have been added. GAs can now flush stats periodically to file or on-demand, and the types of stats that get recorded can be controlled. The interface for recording scores, score buffering, and flushing to file has been revamped. The parameters object has been completely overhauled. It can now read from the command line and/or a settings file using (user definable) strings to set the GA parameters. Since each GA contains a parameters object, these capabilities have also been extended to the GA classes. The base genome class has been cleaned up. In particular, the clone method and dimension enums have been declared in the genome scope to reduce namespace clutter. Also changed are the read/write member functions. They have been renamed (no underscore) and return an integer status. The crossover interface is completely different (see below). Now each genome contains a crossover hint that suggests to a GA how it should mate. By default, the GAs use this information to do the crossovers, but a custom GA can ignore the suggested crossover and do its own mating if it wants to. The equal/not equal members are now public and the underscore has been removed. A compare member function has been added to the genome class. This member function (customizable) provides a mechanism for measuring the diversity of a population. The CrossSite object no longer exists. A new member function, 'crossover', and two access functions, 'sexual' and 'asexual', have taken its place. The crossover function operates on one or two children, so the site information is no longer stored with each genome. The new interface also defines a mechanism for doing asexual reproduction, so it is easier now to implement GAs that use this kind of mating. You can also define crossovers that operate on genomes with mixed data types (this will require a special GA, but you can derive that from one of the standard GA objects then modify the crossover part). The allele set now does reference counting. This allows you to define an allele set in a scope other than the scope in which the genome(s) is defined. It also reduces overhead - each genome does not need to keep its own copy of the allele set. Binary-to-decimal phenotypes now do reference counting. Like the allele sets, phenotypes are needed by many genomes. But there's too much overhead to require each genome to keep its own copy of the phenotype. So now you can create a single phenotype (for your prototype genome) and subsequent clones of your genome will refer to the same phenotype, even if it goes out of scope. A new object, BoundsSet, has been defined to work with the bounded array genome types. It behaves much like an allele set. The constants for tree and list return codes have been rolled into their respective objects to reduce namespace clutter. Genome comparators now return 0 for identical genomes and greater than 0 for completely different genomes. This makes better lexical sense: as the diversity decreases, so does the absolute measure. Notice that previous versions of GAlib expected the opposite measure. I made a number of changes to typedef names to make things more consistent. These changes include: 'GAInitializationOperator' is now 'GAGenome::Initializer' 'GAMutationOperator' is now 'GAGenome::Mutator' 'GADistanceFunction' is now 'GAGenome::Comparator' Changed name of 'GAReplacementGA' to 'GAIncrementalGA'. The functionality of this genetic algorithm type has not changed. Changed the name of 'types.h' to 'gatypes.h' to avoid conflicts with the system types.h file on many platforms. The selection function is now a member of the population object. The signature has not changed, and the selection function is still custimizable, but now housekeeping of population statistics is much more uniform and less convoluted. This also allows you to define a different selection method for each of the populations when using multiple populations. Fixed the bug in the population copy method. The bug caused the population to clone the worst individual multiple times rather than cloning each individual in the population. The patch is descibed in the bugs page. Changing the population size during an evolution now works without the extra call to evaluate. Fixed the bug in the scaling object that prevented the updates after initialization. The patch is descibed in the bugs page. Lots of minor const-correctness tweaks and cleanup of the code, plus fixes of all reported bugs. The new version is marginally faster than the previous. Older versions of the library had problems when objects used by other objects went out of scope. For example, if you created a genome using an allele set then left the scope in which the allele set was active, the genome would refer to garbage. These inconsistencies have been fixed. Objects now make copies of the objects they need, but make no more copies than necessary. There's a whole lot of reference counting and caching going on now. galib247/TODO0100644003643600364360000000207410573535501012125 0ustar mwallmwallthis is a running list of things to be done to galib. todo: - make the library thread-safe - include rules for building both shared and static libraries - remove ancient pseudo rtti cruft - remove accommodations for ancient compilers - xml input and output for saving the state of genomes and evolutions - proper use of namespaces - use double rather than float - allow run-time modification of the random number generator - get rid of all the casts (e.g. GASelector.C) for signed/unsigned - be consistent in use of signed/unsigned in the class apis - use bits for the bit-based genomes so that we reduce memory use by a factor of 8 - enable concurrent builds on the same source tree - make galib 64-bit clean (remove the dangerous casts) - doxygen for all the documentation completed: - fix stream references in examples (includes and cout/cerr) - properly and automatically accommodate both and inclusions - rewrite gaconfig.h to use consistent naming for options and make clear which are defaults, e.g. USE_ANSI_HEADERS/USE_NO_ANSI_HEADERS. galib247/VERSION0100644003643600000000000000000610573536000012433 0ustar mwallwheel2.4.7