/* ---------------------------------------------------------------------------- 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 // 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 #if defined(__GNUG__) template class GAList; template class GA1DArrayGenome; #else GAList; GA1DArrayGenome; #endif #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); }