Developed by Matthew Wall at MIT Collection of
• • Developed by Matthew Wall at MIT Collection of C++ GA components Contains a very nice OOP interface Contains many built-in chromosome type Can be used with PVM Overlapping and non-overlapping are supported Customizable chromosome types, mutation, objective , and crossover functions. • Well written documentation and manuals
Although chromosomes can be built from any C++ type, there exists a large collection of templated built-in types for immediate use. ·GA 1 DArray. Genome<T> ·GA 1 DBinary. String. Genome ·GAList. Genome<T> ·GAReal. Genome ·GAString. Genome ·GATree. Genome<T>
Let V and E represent the vertex and edge sets respectively of a graph. A vertex-cover of an undirected graph G=(V, E) is a subset V’ of V such that if (u, v) is in E then either u or v is an element of V’. The optimal vertex-cover problem is to find a vertex-cover that is minimal in size. Graph( {a, b, c, d, e, f}, { {a, b}, {a, c}, {a, e}, {a, f}, {b, c}, {b, d}, {b, e}, {b, f}, {c, e}, {e, f} } ): The vertex cover is: {a, b, e} and is of optimal size. b d a f e c
float Objective(GAGenome &); // Name of objective function int leng = 20; // Number of vertices in graph int popsize = 100; // number of chromosomes in pop. int ngen = 500; // maximum number of generations float pmut = 0. 001; // probability of mutation float pcross = 0. 7; // probability of crossover GA 1 DBinary. String. Genome genome(leng, Objective);
// This is the name of the function that defines the stopping criteria of the program. ga. terminator(GATerminate. Upon. Generation); ga. population. Size(popsize); // Defines pop size ga. n. Generations(ngen); // Defines the max number of generations to run ga. p. Mutation(pmut); // Mutation probibility ga. p. Crossover(pcross); // Crossover probability ga. evolve(); // Run the GA! // Complete the program by printing out the important information cout << "The GA found: " << ga. statistics(). best. Individual() << "n"; cout << "Other statsn"<<ga. statistics();
//Create genetic algorithm object ga using defined genome GASimple. GA ga(genome); // tells the ga to copy the best individual from previous pop to // to the current population. ga. elitist(ga. True);
float Objective(GAGenome& g) { GA 1 DBinary. String. Genome & genome = (GA 1 DBinary. String. Genome &)g; float score=0. 0; // Traverse the genome bits for(int i=0; i<genome. length(); i++){ score += genome. gene(i); // count number of 1 bits for(int j=0; j<genome. length(); j++) // Watch for bad edges if((graph[i][j]==1)&&(genome. gene(i)==0) &&(genome. gene(j)==0)) score += 3. 0; // count the number of bad edges by threes. } // Return the fitness return ((500. 0 – score)? 500 -score: 0);
// ex 1. C A very simple example #include <ga/GASimple. GA. h> // we're going to use the simple GA #include <ga/GA 2 DBin. Str. Genome. h> // and the 2 D binary string genome #include <ga/std_stream. h> #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 1nn"; cout << "This program tries to fill a 2 DBinary. String. Genome withn"; cout << "alternating 1 s and 0 s using a Simple. GAnn"; 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<argc; ii++) { if(strcmp(argv[ii++], "seed") == 0) { GARandom. Seed((unsigned int)atoi(argv[ii])); } }
// Declare variables for the GA parameters and set them to some default values. int width = 10; int height = 5; int popsize = 30; int ngen = 400; float pmut = 0. 001; float pcross = 0. 9; // 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 operate on this genome in the // optimization - it just uses it to clone a population of genomes. GA 2 DBinary. String. Genome genome(width, height, Objective); // Now that we have the genome, we create the genetic algorithm and set // its parameters - number of generations, mutation probability, and crossover // probability. And finally we tell it to evolve itself. GASimple. GA ga(genome); ga. population. Size(popsize); ga. n. Generations(ngen); ga. p. Mutation(pmut); ga. p. Crossover(pcross); ga. evolve();
// Now we print out the best genome that the GA found. cout << "The GA found: n" << ga. statistics(). best. Individual() << "n"; // That's it! system("pause"); return 0; } float Objective(GAGenome& g) { GA 2 DBinary. String. Genome & genome = (GA 2 DBinary. String. Genome &)g; float score=0. 0; int count=0; for(int i=0; i<genome. width(); i++){ for(int j=0; j<genome. height(); j++){ if(genome. gene(i, j) == 0 && count%2 == 0) score += 1. 0; if(genome. gene(i, j) == 1 && count%2 != 0) score += 1. 0; count++; } } return score; }
Diaphantine Example using Allele Sets /* --------------------------------------Diaphantine. C Programmed by Richard P. Simpson Midwestern State University, Department of Computer Science DESCRIPTION: Linear Diaphantine Equations This is an example program using GALib. It will search for the solution of a Diaphantine Equation 101=2 b+ 3 c+4 d+5 e+6 f. It uses allele sets in the solution restricting the range of a-f to between 0 and 100. Since the gcd of the coeficents is 1 we should have solutions -------------------------------------- */ #include <stdio. h> #include <math. h> #include <iostream> #define TOTAL 101 #define CHROMSIZE 9 #include <ga/GASimple. GA. h> // we're going to use an overlapping GA #include <ga/GA 1 DArray. Genome. h> // and the 1 D binary string genome float Objective(GAGenome &); // This is the declaration of our obj function. // The definition comes later in the file. GABoolean GATerminate. Upon. Generation(GAGenetic. Algorithm & ga);
Start of Main void main(int argc, char **argv) { cout << "This program tries to discover the best possible solnn"; cout << "to the diaphantine equation 101=a+2 b+3 c+4 d+5 e+6 f+7 g+8 h+9 in"; // 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; ii++) { // This seed is set on the command line. WHERE is that in the compiler? if(strcmp(argv[ii++], "seed") == 0) { GARandom. Seed((unsigned int)atoi(argv[ii])); } } ANSWER: under Project|Settings|Debug
main continued // Declare variables for the GA parameters and set them to some default values. int leng = CHROMSIZE; // This represents a graph of 20 vertices int popsize = 200; int ngen = 500; // Set the maximum number of generations to 500; float pmut = 0. 05; // This is the probability of mutation float pcross = 0. 7; // This is the probability of applying a crossover // Now we first create the allele sets for the range 1 to 100 GAAllele. Set<int> range; // Load the Allele set for(int x=1; x<=TOTAL-1; x++)range. add(x);
main continued // 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 operate on this genome in the // optimization - it just uses it to clone a population of genomes. //Create the genome object GA 1 DArray. Allele. Genome<int> genome(leng, range, Objective); //Set appropriate parameters for the genome. initializer(GA 1 DArray. Allele. Genome<int>: : Uniform. Initializer); genome. mutator(GA 1 DArray. Allele. Genome<int>: : Flip. Mutator); genome. crossover(GA 1 DArray. Genome<int>: : One. Point. Crossover);
main continued // Now that we have the genome, we create the genetic algorithm and set // its parameters - number of generations, mutation probability, and crossover // probability. And finally we tell it to evolve itself. GASimple. GA ga(genome); ga. elitist(ga. True); ga. terminator(GATerminate. Upon. Generation); ga. population. Size(popsize); ga. n. Generations(ngen); ga. p. Mutation(pmut); ga. p. Crossover(pcross); ga. evolve();
main continued // Now we print out the best genome that the GA found. GA 1 DArray. Allele. Genome<int> & mygenome = (GA 1 DArray. Allele. Genome<int> &)ga. statistics(). best. Individual(); cout << "The GA found: n" << ga. statistics(). best. Individual() << " "; cout<< "Its sum is: "; int s=0; for(int k=0; k<mygenome. length(); k++) s+= (k+1)*mygenome. gene(k); cout<< s<<endl; cout << "Its fitness is "<< ga. statistics(). max. Ever() << "n"; cout << "Found on generation "<<ga. statistics(). generation()<<"n"; // That's it! }
The terminate function //Here we specify when we want to quit. IE when our best individual has // and fitness of. 999999 or greater. GABoolean. GATerminate. Upon. Generation(GAGenetic. Algorithm & ga){ if(ga. statistics(). max. Ever() >=. 999999) return ga. True; else return ga. False; }
Objective function // This is the objective function. All it does is to check the fitness // of each chromosome by subtracting from 500 the number of ones in the // genome and the number of bad edges. A bad edge is one whose end points // are not represented in the genome. // We have to do the cast because a plain, generic GAGenome doesn't have // the members that a GA 1 DBinary. String. Genome has. And it's ok to cast it // because we know that we will only get GA 1 DBinary. String. Genomes and // nothing else. float Objective(GAGenome& g) { GA 1 DArray. Allele. Genome<int> & genome = (GA 1 DArray. Allele. Genome<int> &)g; float score=0. 0; for(int i=0; i<genome. length(); i++){ score += (i+1)*genome. gene(i); // Evaluate functions } return (1/(1. 0+fabs(TOTAL - score))); }
- Slides: 19