200 likes | 225 Views
GAlib. 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.
E N D
GAlib • 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
Example GAlib Chromosome Types • Although chromosomes can be built from any C++ type, there exists a large collection of templated built-in types for immediate use. • GA1DArrayGenome<T> • GA1DBinaryStringGenome • GAListGenome<T> • GARealGenome • GAStringGenome • GATreeGenome<T>
Example Problem: Optimal Vertex Cover 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} } ): d a b The vertex cover is: {a,b,e} and is of optimal size. f e c
Early Program Initializations float Objective(GAGenome &); // Name of objectivefunction 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 GA1DBinaryStringGenome genome(leng,Objective);
Initialize the ga parameters // This is the name of the function that defines the stopping criteria of the program. ga.terminator(GATerminateUponGeneration); ga.populationSize(popsize);// Defines pop size ga.nGenerations(ngen);// Defines the max number of generations to run ga.pMutation(pmut);// Mutation probibility ga.pCrossover(pcross);// Crossover probability ga.evolve();// Run the GA! // Complete the program by printing out the important information cout << "The GA found:" << ga.statistics().bestIndividual() << "\n"; cout << "Other stats\n"<<ga.statistics();
Create the ga object //Create genetic algorithm object ga using defined genome GASimpleGA ga(genome); // tells the ga to copy the best individual from previous pop to // to the current population. ga.elitist(gaTrue);
The Fitness Function • float Objective(GAGenome& g) { • GA1DBinaryStringGenome & genome = (GA1DBinaryStringGenome &)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);
// ex1.C A very simple example #include <ga/GASimpleGA.h> // we're going to use the simple GA #include <ga/GA2DBinStrGenome.h> // and the 2D 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(intargc, 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<argc; ii++) { if(strcmp(argv[ii++],"seed") == 0) { GARandomSeed((unsigned int)atoi(argv[ii])); } }
// Declare variables for the GA parameters and set them to some default values. int width = 10; int height = 5; intpopsize = 30; intngen = 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. GA2DBinaryStringGenome 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. GASimpleGAga(genome); ga.populationSize(popsize); ga.nGenerations(ngen); ga.pMutation(pmut); ga.pCrossover(pcross); ga.evolve();
// Now we print out the best genome that the GA found. cout << "The GA found:\n" << ga.statistics().bestIndividual() << "\n"; // That's it! system("pause"); return 0; } float Objective(GAGenome& g) { GA2DBinaryStringGenome & genome = (GA2DBinaryStringGenome &)g; float score=0.0; int count=0; for(inti=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 Exampleusing 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=2b+ 3c+4d+5e+6f. 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/GASimpleGA.h> // we're going to use an overlapping GA #include <ga/GA1DArrayGenome.h> // and the 1D binary string genome float Objective(GAGenome &); // This is the declaration of our obj function.// The definition comes later in the file. GABoolean GATerminateUponGeneration(GAGeneticAlgorithm & ga);
Start of Main void main(int argc, char **argv) { cout << "This program tries to discover the best possible soln\n"; cout << "to the diaphantine equation 101=a+2b+3c+4d+5e+6f+7g+8h+9i\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; ii++) { // This seed is set on the command line. WHERE is that in the compiler? if(strcmp(argv[ii++],"seed") == 0) { GARandomSeed((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 GAAlleleSet<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 GA1DArrayAlleleGenome<int> genome(leng, range, Objective); //Set appropriate parameters for the genome genome.initializer(GA1DArrayAlleleGenome<int>::UniformInitializer); genome.mutator(GA1DArrayAlleleGenome<int>::FlipMutator); genome.crossover(GA1DArrayGenome<int>::OnePointCrossover);
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. GASimpleGA ga(genome); ga.elitist(gaTrue); ga.terminator(GATerminateUponGeneration); ga.populationSize(popsize); ga.nGenerations(ngen); ga.pMutation(pmut); ga.pCrossover(pcross); ga.evolve();
main continued // Now we print out the best genome that the GA found. GA1DArrayAlleleGenome<int> & mygenome = (GA1DArrayAlleleGenome<int> &)ga.statistics().bestIndividual(); cout << "The GA found:\n" << ga.statistics().bestIndividual() << " "; 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().maxEver() << "\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. GABooleanGATerminateUponGeneration(GAGeneticAlgorithm & ga){ if(ga.statistics().maxEver() >=.999999) return gaTrue; else return gaFalse; }
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 GA1DBinaryStringGenome has. And it's ok to cast it // because we know that we will only get GA1DBinaryStringGenomes and // nothing else. float Objective(GAGenome& g) { GA1DArrayAlleleGenome<int> & genome = (GA1DArrayAlleleGenome<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))); }
Modern Evolution The End