// 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; i<tmpPop->size()-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; 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 // 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; i<tmpPop->size(); i++) tmpPop->replace(pop->remove(GAPopulation::WORST, GAPopulation::SCALED), i); stats.numrep += tmpPop->size(); stats.update(*pop); // update the statistics by one generation }
// 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 }
// 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; i<pop->size()-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; } // Pass mpi_tasks and mpi_rank to the population clas pop->mpi_tasks(vmpi_tasks); pop->mpi_rank(vmpi_rank); 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 }
// Return 0 if everything is OK, non-zero if error. If we did not set anything // then we return non-zero (this is not an error, but we indicate that we did // not do anything). // The set method must set both the GA's parameter and the value in the // parameter list (kind of stupid to maintain two copies of the same data, but // oh well). The call to set on params is redundant for the times when this // method is called *after* the parameter list has been updated, but it is // necessary when this method is called directly by the user. int GAGeneticAlgorithm::setptr(const char* name, const void* value){ int status=1; params.set(name, value); // redundant for some cases, but not others if(strcmp(name, gaNnBestGenomes) == 0 || strcmp(name, gaSNnBestGenomes) == 0){ #ifdef GA_DEBUG cerr << "GAGeneticAlgorithm::setptr\n setting '" << name << "' to '" << *((int*)value) << "'\n"; #endif nBestGenomes(*((int*)value)); status = 0; } else if(strcmp(name, gaNpopulationSize) == 0 || strcmp(name, gaSNpopulationSize) == 0){ #ifdef GA_DEBUG cerr << "GAGeneticAlgorithm::setptr\n setting '" << name << "' to '" << *((int*)value) << "'\n"; #endif populationSize(*((int*)value)); status = 0; } else if(strcmp(name, gaNminimaxi) == 0 || strcmp(name, gaSNminimaxi) == 0){ #ifdef GA_DEBUG cerr << "GAGeneticAlgorithm::setptr\n setting '" << name << "' to '" << *((int*)value) << "'\n"; #endif minimaxi(*((int*)value)); status = 0; } else if(strcmp(name, gaNnGenerations) == 0 || strcmp(name, gaSNnGenerations) == 0){ #ifdef GA_DEBUG cerr << "GAGeneticAlgorithm::setptr\n setting '" << name << "' to '" << *((int*)value) << "'\n"; #endif nGenerations(*((int*)value)); status = 0; } else if(strcmp(name, gaNpConvergence) == 0 || strcmp(name, gaSNpConvergence) == 0){ #ifdef GA_DEBUG cerr << "GAGeneticAlgorithm::setptr\n setting '" << name << "' to '" << *((float*)value) << "'\n"; #endif pConvergence(*((float*)value)); status = 0; } else if(strcmp(name, gaNnConvergence) == 0 || strcmp(name, gaSNnConvergence) == 0){ #ifdef GA_DEBUG cerr << "GAGeneticAlgorithm::setptr\n setting '" << name << "' to '" << *((int*)value) << "'\n"; #endif nConvergence(*((int*)value)); status = 0; } else if(strcmp(name, gaNpCrossover) == 0 || strcmp(name, gaSNpCrossover) == 0){ #ifdef GA_DEBUG cerr << "GAGeneticAlgorithm::setptr\n setting '" << name << "' to '" << *((float*)value) << "'\n"; #endif pCrossover(*((float*)value)); status = 0; } else if(strcmp(name, gaNpMutation) == 0 || strcmp(name, gaSNpMutation) == 0){ #ifdef GA_DEBUG cerr << "GAGeneticAlgorithm::setptr\n setting '" << name << "' to '" << *((float*)value) << "'\n"; #endif pMutation(*((float*)value)); status = 0; } else if(strcmp(name,gaNscoreFrequency) == 0 || strcmp(name,gaSNscoreFrequency) == 0){ #ifdef GA_DEBUG cerr << "GAGeneticAlgorithm::setptr\n setting '" << name << "' to '" << *((int*)value) << "'\n"; #endif stats.scoreFrequency(*((int*)value)); status = 0; } else if(strcmp(name,gaNflushFrequency) == 0 || strcmp(name,gaSNflushFrequency) == 0){ #ifdef GA_DEBUG cerr << "GAGeneticAlgorithm::setptr\n setting '" << name << "' to '" << *((int*)value) << "'\n"; #endif stats.flushFrequency(*((int*)value)); status = 0; } else if(strcmp(name,gaNrecordDiversity) == 0 || strcmp(name,gaSNrecordDiversity) == 0){ #ifdef GA_DEBUG cerr << "GAGeneticAlgorithm::setptr\n setting '" << name << "' to '" << *((int*)value) << "'\n"; #endif stats.recordDiversity(*((int*)value) ? gaTrue : gaFalse); status = 0; } else if(strcmp(name,gaNselectScores) == 0 || strcmp(name,gaSNselectScores)==0){ #ifdef GA_DEBUG cerr << "GAGeneticAlgorithm::setptr\n setting '" << name << "' to '" << *((int*)value) << "'\n"; #endif stats.selectScores(*((int*)value)); status = 0; } else if(strcmp(name,gaNscoreFilename) == 0 || strcmp(name,gaSNscoreFilename) == 0){ #ifdef GA_DEBUG cerr << "GAGeneticAlgorithm::setptr\n setting '" << name << "' to '" << ((char*)value) << "'\n"; #endif char tmpname[64]; memcpy(tmpname, value, strlen((char*)value)+1); stats.scoreFilename(tmpname); status = 0; } return status; }
// 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; ii<npop; ii++) { for(i=0; i<nrepl[ii]-1; i+=2){ // takes care of odd population mom = &(deme[ii]->select()); 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; i<nrepl[ii]; i++) deme[ii]->add(&tmppop->individual(i)); deme[ii]->evaluate(); deme[ii]->scale(); for(i=0; i<nrepl[ii]; i++) tmppop->replace(deme[ii]->remove(GAPopulation::WORST, GAPopulation::SCALED), i); pstats[ii].numrep += nrepl[ii]; } migrate(); for(unsigned int jj=0; jj<npop; jj++) { deme[jj]->evaluate(); pstats[jj].update(*deme[jj]); } stats.numsel = stats.numcro = stats.nummut = stats.numrep = stats.numeval=0; for(unsigned int kk=0; kk<npop; kk++) { pop->individual(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; ll<npop; ll++) stats.numpeval += pstats[ll].numpeval; }