[ Home | Docs | News | Resources | Download]
GAUL Documentation: GA Operators

It is now time to look at the parameters to the "ga_genesis_char()" (and the other genesis functions, including "ga_genesis_bitstring()" "ga_genesis_integer()", "ga_genesis_double()" and so on).

The function prototype for the genesis functions, where XXX relates to the built-in chromosome type, is:

population *ga_genesis_XXX( const int               population_size,
                            const int               num_chromo,
                            const int               len_chromo,
                            GAgeneration_hook       generation_hook,
                            GAiteration_hook        iteration_hook,
                            GAdata_destructor       data_destructor,
                            GAdata_ref_incrementor  data_ref_incrementor,
                            GAevaluate              evaluate,
                            GAseed                  seed,
                            GAadapt                 adapt,
                            GAselect_one            select_one,
                            GAselect_two            select_two,
                            GAmutate                mutate,
                            GAcrossover             crossover,
                            GAreplace               replace,
                            void                    userdata );

Basic parameters

The "population_size" parameter defines the stable size for the population At any given time the population may be a different size, but this is the maximum number of individuals which will pass into a subsequent generation.

The "num_chromo" parameter specifies the number of chromosomes in the genome.

The "len_chromo" parameter specifies the length of each chromosome, but the exact definition of length is dependent on the chromosome type. Some chromosome types may ignore this value entirely.

Analysis functions

"generation_hook" and "iteration_hook" specify callback functions will be called at the beginning of each generation of evolutionary procedures, and each iteration of deterministic optimisation procedures, respectively. These may safely be defined as "NULL" functions. As described earlier, these functions may also be used to implement custom termination criteria. "generation_hook" applies to evolutionary algorithms while "iteration_hook" applies to the non-evolutionary algorithms, such as the simplex search.

Phenome handling functions

"data_destructor" and "data_ref_incrementor" specify callback functions which handle memory allocation for user defined (phenomic) data. These may safely be defined as "NULL" functions, in which case the phenomes are assumed to be either static data, or empty.

GA operator functions

The remainder of the parameters define the set of genetic algorithm operators. Either the built-in functions, or custom functions may be used. It is perfectly safe to modify the specified functions during an evolutionary run. As an example of this, we swap between single-point and double-point crossover in the code below. You may wish to dynamically switch the scoring function, and this is also possible.

Several commonly used algorithms are provided by GAUL for use as these callback functions. These are all described in a later section of this tutorial and in the reference guide. Any programmer using GAUL is also able to define their own replacements or specialised versions.

Lower-level functions

The genesis functions are high-level convenience functions which encapsulate several lower level GAUL functions. Sometimes you will need more fine control over the population setup. Below, a set of equivalent low-level GAUL functions are explained. These would give you, say, the ability do do things like seed the initial population from a file on disk. The source code for this extended example is struggle4.c.

Our new "main()" function and a set of custom operator functions is:


/* Define a pair of crossover operators which will be called alternately. */
void the_other_struggle_crossover( population *pop,
                        entity *father, entity *mother,
                        entity *son, entity *daughter )
  {
  ga_crossover_char_singlepoints(pop, father, mother, son, daughter);
  pop->crossover = struggle_crossover;

  return;
  }

void struggle_crossover( population *pop,
                        entity *father, entity *mother,
                        entity *son, entity *daughter )
  {
  ga_crossover_char_doublepoints(pop, father, mother, son, daughter);
  pop->crossover = the_other_struggle_crossover;

  return;
  }

int main(int argc, char **argv)
  {
  population    *pop=NULL;      /* Population structure. */

  random_init();
  random_seed(23091975);

/*
 * Allocate a new popuation structure.
 * stable num. individuals = 100.
 * num. chromosomes = 1.
 * length of chromosomes = strlen(target_text);
 */
  pop = ga_population_new( 100, 1, strlen(target_text) );

  if ( !pop ) die("Unable to allocate population.");

/*
 * Define chromosome handling functions.
 * Normally these functions would only be set manually when
 * creating a custom chromosome type.
 */
  pop->chromosome_constructor = ga_chromosome_char_allocate;
  pop->chromosome_destructor = ga_chromosome_char_deallocate;
  pop->chromosome_replicate = ga_chromosome_char_replicate;
  pop->chromosome_to_bytes = ga_chromosome_char_to_bytes;
  pop->chromosome_from_bytes = ga_chromosome_char_from_bytes;
  pop->chromosome_to_string = ga_chromosome_char_to_string;
  
/* Define all the needed callback functions. */
  pop->generation_hook = NULL;
  pop->iteration_hook = NULL;
  pop->data_destructor = NULL;
  pop->data_ref_incrementor = NULL;

/* Fitness evaluation. */
  pop->evaluate = struggle_score;

/* Individual initialisation. */
  pop->seed = struggle_seed;

/* Environmental adaptation operator. */
  pop->adapt = struggle_adaptation;

/* Mutation selection operator. */
  pop->select_one = ga_select_one_roulette;

/* Crossover selection operator. */
  pop->select_two = ga_select_two_roulette;

/* Mutation operator. */
  pop->mutate = struggle_mutate;

/* Crossover operator. */
  pop->crossover = struggle_crossover;

/* Replacement operator. (Only used in steady-state evolution) */
  pop->replace = NULL;

/*
 * Seed the initial population. (Could do this manually - it
 * just calls pop->seed() 100 times in this case.)
 */
  ga_population_seed(pop);

/*
 * Set the GA parameters.
 * Lamarkian evolution.
 * Parents may survive into next generation.
 * Crossover ratio = 0.9.
 * Mutation ratio = 0.1.
 * Migration ration = 0.0.
 *
 * Note that custom operator functions may choose to ignore these values.
 *
 * There are functions for setting these individually too.
 */
  ga_population_set_parameters( pop, GA_SCHEME_LAMARCK, GA_ELITISM_PARENTS_SURVIVE, 0.9, 0.1, 0.0 );

/* Perform 500 generations. */
  ga_evolution( pop, 500 );

  printf( "The final solution with score %f was:\n",
          ga_get_entity_from_rank(pop,0)->fitness );
  beststring = ga_chromosome_char_to_string(pop, ga_get_entity_from_rank(pop,0), beststring, &beststrlen);
  printf("%s\n", beststring);

/*
 * This deallocates the population, all individuals, and
 * any genomic and phenomic data that may be associated.
 * (Not quite true - it actually dereferences any phenomic
 * data, which will then be deallocated if appropriate.)
 */
  ga_extinction(pop);

  s_free(beststring);

  exit(EXIT_SUCCESS);
  }

Custom selection operators are discussed in a later section of this tutorial.

[ BACK TO TOP | NEXT SECTION OF TUTORIAL ]

[ Home | Docs | News | Resources | Download]
Hosted by:
SourceForge Logo
GAUL Button Valid HTML 4.01!

© 2001-2005, "Stewart Adcock" <stewart@linux-domain.com> All rights reserved.
All trademarks on this page are probably owned by their respective companies. You can insert you own favourite disclaimer here.