// This is a an implementation of a uniform crossover for the binary string. // It assumes that the the genomes are all the same length. int BitStringGenome::UniformCrossover(const GAGenome& a, const GAGenome& b, GAGenome* c, GAGenome* d) { BitStringGenome& mom=(BitStringGenome &)a; BitStringGenome& dad=(BitStringGenome &)b; int n = 0; if(c && d){ BitStringGenome& sis=(BitStringGenome &)*c; BitStringGenome& bro=(BitStringGenome &)*d; for(int i=sis.length()-1; i>=0; i--){ if(GARandomBit()){ sis.gene(i, mom.gene(i)); bro.gene(i, dad.gene(i)); } else{ sis.gene(i, dad.gene(i)); bro.gene(i, mom.gene(i)); } } n = 2; } else { BitStringGenome& sis = (c ? (BitStringGenome&)*c : (BitStringGenome&)*d); for(int i=sis.length()-1; i>=0; i--) sis.gene(i, (GARandomBit() ? mom.gene(i) : dad.gene(i))); n = 1; } return n; }
int GA2DBinaryStringGenome::resize(int w, int h) { if((unsigned int)w == nx && (unsigned int)h == ny) return sz; if(w == GAGenome::ANY_SIZE) w = GARandomInt(minX, maxX); else if(w < 0) w = nx; // do nothing else if(minX == maxX) minX=maxX = w; else{ if(w < STA_CAST(int, minX)) w=minX; if(w > STA_CAST(int, maxX)) w=maxX; } if(h == GAGenome::ANY_SIZE) h = GARandomInt(minY, maxY); else if(h < 0) h = ny; // do nothing else if(minY == maxY) minY=maxY = h; else{ if(h < STA_CAST(int, minY)) h=minY; if(h > STA_CAST(int, maxY)) h=maxY; } // Move the bits into the right position. If we're smaller, then shift to // the smaller size before we do the resize (the resize method maintains bit // integrety). If we're larger, do the move after the resize. If we're the // same size the we don't do anything. When we're adding more bits, the new // bits get set randomly to 0 or 1. if(w < STA_CAST(int,nx)){ int y=GAMin(STA_CAST(int,ny),h); for(int j=0; j<y; j++) GABinaryString::move(j*w,j*nx,w); } GABinaryString::resize(w*h); if(w > STA_CAST(int,nx)){ // adjust the existing chunks of bits int y=GAMin(STA_CAST(int,ny),h); for(int j=y-1; j>=0; j--){ GABinaryString::move(j*w,j*nx,nx); for(int i=nx; i<w; i++) bit(j*w+i, GARandomBit()); } } if(h > STA_CAST(int,ny)){ // change in height is always new bits for(int i=w*ny; i<w*h; i++) bit(i, GARandomBit()); } nx = w; ny = h; _evaluated = gaFalse; return sz; }
/* ---------------------------------------------------------------------------- 3D Binary String Genome The order for looping through indices is depth-then-height-then-width (ie depth loops before a single height increment, height loops before a single width increment) ---------------------------------------------------------------------------- */ void GA3DBinaryStringGenome::UniformInitializer(GAGenome & c) { GA3DBinaryStringGenome &child=(GA3DBinaryStringGenome &)c; child.resize(GAGenome::ANY_SIZE,GAGenome::ANY_SIZE,GAGenome::ANY_SIZE); for(int i=child.width()-1; i>=0; i--) for(int j=child.height()-1; j>=0; j--) for(int k=child.depth()-1; k>=0; k--) child.gene(i,j,k, GARandomBit()); }
// Resize the genome. If someone specifies ANY_RESIZE then we pick a random // size within the behaviour limits that have been set. If limits have been // set and someone passes us something outside the limits, we resize to the // closest bound. If the genome is fixed size (ie min limit equals max limit) // then we resize to the specified value and move the min/max to match it. int GA1DBinaryStringGenome::resize(int l) { if(l == STA_CAST(int, nx)) return nx; if(l == GAGenome::ANY_SIZE) l = GARandomInt(minX, maxX); else if(l < 0) return nx; // do nothing else if(minX == maxX) minX=maxX=l; else{ if(l < STA_CAST(int, minX)) l=minX; if(l > STA_CAST(int, maxX)) l=maxX; } GABinaryString::resize(l); if(l > STA_CAST(int, nx)) for(int i=nx; i<l; i++) bit(i, GARandomBit()); nx = l; _evaluated = gaFalse; return sz; }
// 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 }
// The random initializer sets the bits in the bit string randomly to 0 or 1. // It uses the GARandomBit function to do this (GARandomBit is pretty efficient // in terms of its calls to your system's random function). void BitStringGenome::UniformInitializer(GAGenome & c) { BitStringGenome &genome=(BitStringGenome &)c; for(int i=genome.length()-1; i>=0; i--) genome.gene(i, GARandomBit()); }
// 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 }
// Pick a single point in the 3D block and grab alternating quadrants for each // child. If the children are resizable, this crossover does clipping. template <class T> int GA3DArrayGenome<T>:: OnePointCrossover(const GAGenome& p1, const GAGenome& p2, GAGenome* c1, GAGenome* c2){ GA3DArrayGenome<T> &mom=(GA3DArrayGenome<T> &)p1; GA3DArrayGenome<T> &dad=(GA3DArrayGenome<T> &)p2; int nc=0; unsigned int momsitex, momlenx, momsitey, momleny, momsitez, momlenz; unsigned int dadsitex, dadlenx, dadsitey, dadleny, dadsitez, dadlenz; unsigned int sitex, lenx, sitey, leny, sitez, lenz; if(c1 && c2){ GA3DArrayGenome<T> &sis=(GA3DArrayGenome<T> &)*c1; GA3DArrayGenome<T> &bro=(GA3DArrayGenome<T> &)*c2; if(sis.resizeBehaviour(GAGenome::WIDTH) == GAGenome::FIXED_SIZE && bro.resizeBehaviour(GAGenome::WIDTH) == GAGenome::FIXED_SIZE){ if(mom.width() != dad.width() || sis.width() != bro.width() || sis.width() != mom.width()){ GAErr(GA_LOC, mom.className(), "one-point cross", gaErrSameLengthReqd); return nc; } sitex = momsitex = dadsitex = GARandomInt(0, mom.width()); lenx = momlenx = dadlenx = mom.width() - momsitex; } else if(sis.resizeBehaviour(GAGenome::WIDTH) == GAGenome::FIXED_SIZE || bro.resizeBehaviour(GAGenome::WIDTH) == GAGenome::FIXED_SIZE){ GAErr(GA_LOC, mom.className(), "one-point cross", gaErrSameBehavReqd); return nc; } else{ momsitex = GARandomInt(0, mom.width()); dadsitex = GARandomInt(0, dad.width()); momlenx = mom.width() - momsitex; dadlenx = dad.width() - dadsitex; sitex = GAMin(momsitex, dadsitex); lenx = GAMin(momlenx, dadlenx); } if(sis.resizeBehaviour(GAGenome::HEIGHT) == GAGenome::FIXED_SIZE && bro.resizeBehaviour(GAGenome::HEIGHT) == GAGenome::FIXED_SIZE){ if(mom.height() != dad.height() || sis.height() != bro.height() || sis.height() != mom.height()){ GAErr(GA_LOC, mom.className(), "one-point cross", gaErrSameLengthReqd); return nc; } sitey = momsitey = dadsitey = GARandomInt(0, mom.height()); leny = momleny = dadleny = mom.height() - momsitey; } else if(sis.resizeBehaviour(GAGenome::HEIGHT) == GAGenome::FIXED_SIZE || bro.resizeBehaviour(GAGenome::HEIGHT) == GAGenome::FIXED_SIZE){ GAErr(GA_LOC, mom.className(), "one-point cross", gaErrSameBehavReqd); return nc; } else{ momsitey = GARandomInt(0, mom.height()); dadsitey = GARandomInt(0, dad.height()); momleny = mom.height() - momsitey; dadleny = dad.height() - dadsitey; sitey = GAMin(momsitey, dadsitey); leny = GAMin(momleny, dadleny); } if(sis.resizeBehaviour(GAGenome::DEPTH) == GAGenome::FIXED_SIZE && bro.resizeBehaviour(GAGenome::DEPTH) == GAGenome::FIXED_SIZE){ if(mom.depth() != dad.depth() || sis.depth() != bro.depth() || sis.depth() != mom.depth()){ GAErr(GA_LOC, mom.className(), "one-point cross", gaErrSameLengthReqd); return nc; } sitez = momsitez = dadsitez = GARandomInt(0, mom.depth()); lenz = momlenz = dadlenz = mom.depth() - momsitez; } else if(sis.resizeBehaviour(GAGenome::DEPTH) == GAGenome::FIXED_SIZE || bro.resizeBehaviour(GAGenome::DEPTH) == GAGenome::FIXED_SIZE){ GAErr(GA_LOC, mom.className(), "one-point cross", gaErrSameBehavReqd); return nc; } else{ momsitez = GARandomInt(0, mom.depth()); dadsitez = GARandomInt(0, dad.depth()); momlenz = mom.depth() - momsitez; dadlenz = dad.depth() - dadsitez; sitez = GAMin(momsitez, dadsitez); lenz = GAMin(momlenz, dadlenz); } sis.resize(sitex+lenx, sitey+leny, sitez+lenz); bro.resize(sitex+lenx, sitey+leny, sitez+lenz); sis.copy(mom, 0, 0, 0, momsitex-sitex, momsitey-sitey, momsitez-sitez, sitex, sitey, sitez); sis.copy(dad, sitex, 0, 0, dadsitex, dadsitey-sitey, dadsitez-sitez, lenx, sitey, sitez); sis.copy(dad, 0, sitey, 0, dadsitex-sitex, dadsitey, dadsitez-sitez, sitex, leny, sitez); sis.copy(mom, sitex, sitey, 0, momsitex, momsitey, momsitez-sitez, lenx, leny, sitez); sis.copy(dad, 0, 0, sitez, dadsitex-sitex, dadsitey-sitey, dadsitez, sitex, sitey, lenz); sis.copy(mom, sitex, 0, sitez, momsitex, momsitey-sitey, momsitez, lenx, sitey, lenz); sis.copy(mom, 0, sitey, sitez, momsitex-sitex, momsitey, momsitez, sitex, leny, lenz); sis.copy(dad, sitex, sitey, sitez, dadsitex, dadsitey, dadsitez, lenx, leny, lenz); bro.copy(dad, 0, 0, 0, dadsitex-sitex, dadsitey-sitey, dadsitez-sitez, sitex, sitey, sitez); bro.copy(mom, sitex, 0, 0, momsitex, momsitey-sitey, momsitez-sitez, lenx, sitey, sitez); bro.copy(mom, 0, sitey, 0, momsitex-sitex, momsitey, momsitez-sitez, sitex, leny, sitez); bro.copy(dad, sitex, sitey, 0, dadsitex, dadsitey, dadsitez-sitez, lenx, leny, sitez); bro.copy(mom, 0, 0, sitez, momsitex-sitex, momsitey-sitey, momsitez, sitex, sitey, lenz); bro.copy(dad, sitex, 0, sitez, dadsitex, dadsitey-sitey, dadsitez, lenx, sitey, lenz); bro.copy(dad, 0, sitey, sitez, dadsitex-sitex, dadsitey, dadsitez, sitex, leny, lenz); bro.copy(mom, sitex, sitey, sitez, momsitex, momsitey, momsitez, lenx, leny, lenz); nc = 2; } else if(c1){ GA3DArrayGenome<T> &sis=(GA3DArrayGenome<T> &)*c1; if(sis.resizeBehaviour(GAGenome::WIDTH) == GAGenome::FIXED_SIZE){ if(mom.width() != dad.width() || sis.width() != mom.width()){ GAErr(GA_LOC, mom.className(), "one-point cross", gaErrSameLengthReqd); return nc; } sitex = momsitex = dadsitex = GARandomInt(0, mom.width()); lenx = momlenx = dadlenx = mom.width() - momsitex; } else{ momsitex = GARandomInt(0, mom.width()); dadsitex = GARandomInt(0, dad.width()); momlenx = mom.width() - momsitex; dadlenx = dad.width() - dadsitex; sitex = GAMin(momsitex, dadsitex); lenx = GAMin(momlenx, dadlenx); } if(sis.resizeBehaviour(GAGenome::HEIGHT) == GAGenome::FIXED_SIZE){ if(mom.height() != dad.height() || sis.height() != mom.height()){ GAErr(GA_LOC, mom.className(), "one-point cross", gaErrSameLengthReqd); return nc; } sitey = momsitey = dadsitey = GARandomInt(0, mom.height()); leny = momleny = dadleny = mom.height() - momsitey; } else{ momsitey = GARandomInt(0, mom.height()); dadsitey = GARandomInt(0, dad.height()); momleny = mom.height() - momsitey; dadleny = dad.height() - dadsitey; sitey = GAMin(momsitey, dadsitey); leny = GAMin(momleny, dadleny); } if(sis.resizeBehaviour(GAGenome::DEPTH) == GAGenome::FIXED_SIZE){ if(mom.depth() != dad.depth() || sis.depth() != mom.depth()){ GAErr(GA_LOC, mom.className(), "one-point cross", gaErrSameLengthReqd); return nc; } sitez = momsitez = dadsitez = GARandomInt(0, mom.depth()); lenz = momlenz = dadlenz = mom.depth() - momsitez; } else{ momsitez = GARandomInt(0, mom.depth()); dadsitez = GARandomInt(0, dad.depth()); momlenz = mom.depth() - momsitez; dadlenz = dad.depth() - dadsitez; sitez = GAMin(momsitez, dadsitez); lenz = GAMin(momlenz, dadlenz); } sis.resize(sitex+lenx, sitey+leny, sitez+lenz); if(GARandomBit()){ sis.copy(mom, 0, 0, 0, momsitex-sitex, momsitey-sitey, momsitez-sitez, sitex, sitey, sitez); sis.copy(dad, sitex, 0, 0, dadsitex, dadsitey-sitey, dadsitez-sitez, lenx, sitey, sitez); sis.copy(dad, 0, sitey, 0, dadsitex-sitex, dadsitey, dadsitez-sitez, sitex, leny, sitez); sis.copy(mom, sitex, sitey, 0, momsitex, momsitey, momsitez-sitez, lenx, leny, sitez); sis.copy(dad, 0, 0, sitez, dadsitex-sitex, dadsitey-sitey, dadsitez, sitex, sitey, lenz); sis.copy(mom, sitex, 0, sitez, momsitex, momsitey-sitey, momsitez, lenx, sitey, lenz); sis.copy(mom, 0, sitey, sitez, momsitex-sitex, momsitey, momsitez, sitex, leny, lenz); sis.copy(dad, sitex, sitey, sitez, dadsitex, dadsitey, dadsitez, lenx, leny, lenz); } else{ sis.copy(dad, 0, 0, 0, dadsitex-sitex, dadsitey-sitey, dadsitez-sitez, sitex, sitey, sitez); sis.copy(mom, sitex, 0, 0, momsitex, momsitey-sitey, momsitez-sitez, lenx, sitey, sitez); sis.copy(mom, 0, sitey, 0, momsitex-sitex, momsitey, momsitez-sitez, sitex, leny, sitez); sis.copy(dad, sitex, sitey, 0, dadsitex, dadsitey, dadsitez-sitez, lenx, leny, sitez); sis.copy(mom, 0, 0, sitez, momsitex-sitex, momsitey-sitey, momsitez, sitex, sitey, lenz); sis.copy(dad, sitex, 0, sitez, dadsitex, dadsitey-sitey, dadsitez, lenx, sitey, lenz); sis.copy(dad, 0, sitey, sitez, dadsitex-sitex, dadsitey, dadsitez, sitex, leny, lenz); sis.copy(mom, sitex, sitey, sitez, momsitex, momsitey, momsitez, lenx, leny, lenz); } nc = 1; } return nc; }
// Make sure our bitmask is big enough, generate a mask, then use it to // extract the information from each parent to stuff the two children. // We don't deallocate any space for the masks under the assumption that we'll // have to use them again in the future. // For now we'll implement this only for fixed length genomes. If you use // this crossover method on genomes of different sizes it might break! template <class T> int GA3DArrayGenome<T>:: UniformCrossover(const GAGenome& p1, const GAGenome& p2, GAGenome* c1, GAGenome* c2){ GA3DArrayGenome<T> &mom=(GA3DArrayGenome<T> &)p1; GA3DArrayGenome<T> &dad=(GA3DArrayGenome<T> &)p2; int nc=0; int i,j,k; if(c1 && c2){ GA3DArrayGenome<T> &sis=(GA3DArrayGenome<T> &)*c1; GA3DArrayGenome<T> &bro=(GA3DArrayGenome<T> &)*c2; if(sis.width() == bro.width() && sis.height() == bro.height() && sis.depth() == bro.depth() && mom.width() == dad.width() && mom.height() == dad.height() && mom.depth() == dad.depth() && sis.width() == mom.width() && sis.height() == mom.height() && sis.depth() == mom.depth()){ for(i=sis.width()-1; i>=0; i--){ for(j=sis.height()-1; j>=0; j--){ for(k=sis.depth()-1; k>=0; k--){ if(GARandomBit()){ sis.gene(i,j,k, mom.gene(i,j,k)); bro.gene(i,j,k, dad.gene(i,j,k)); } else{ sis.gene(i,j,k, dad.gene(i,j,k)); bro.gene(i,j,k, mom.gene(i,j,k)); } } } } } else{ GAMask mask; int startx, starty, startz; int maxx = (sis.width() > bro.width()) ? sis.width() : bro.width(); int minx = (mom.width() < dad.width()) ? mom.width() : dad.width(); int maxy = (sis.height() > bro.height()) ? sis.height() : bro.height(); int miny = (mom.height() < dad.height()) ? mom.height() : dad.height(); int maxz = (sis.depth() > bro.depth()) ? sis.depth() : bro.depth(); int minz = (mom.depth() < dad.depth()) ? mom.depth() : dad.depth(); mask.size(maxx*maxy*maxz); for(i=0; i<maxx; i++) for(j=0; j<maxy; j++) for(k=0; k<maxz; k++) mask[i*maxy*maxz+j*maxz+k] = GARandomBit(); startx = (sis.width() < minx) ? sis.width() : minx; starty = (sis.height() < miny) ? sis.height() : miny; startz = (sis.depth() < minz) ? sis.depth() : minz; for(i=startx-1; i>=0; i--) for(j=starty-1; j>=0; j--) for(k=startz-1; k>=0; k--) sis.gene(i,j,k, (mask[i*starty*startz+j*startz+k] ? mom.gene(i,j,k) : dad.gene(i,j,k))); startx = (bro.width() < minx) ? bro.width() : minx; starty = (bro.height() < miny) ? bro.height() : miny; startz = (bro.depth() < minz) ? bro.depth() : minz; for(i=startx-1; i>=0; i--) for(j=starty-1; j>=0; j--) for(k=startz-1; k>=0; k--) bro.gene(i,j,k, (mask[i*starty*startz+j*startz+k] ? dad.gene(i,j,k) : mom.gene(i,j,k))); } nc = 2; } else if(c1){ GA3DArrayGenome<T> &sis=(GA3DArrayGenome<T> &)*c1; if(mom.width() == dad.width() && mom.height() == dad.height() && mom.depth() == dad.depth() && sis.width() == mom.width() && sis.height() == mom.height() && sis.depth() == mom.depth()){ for(i=sis.width()-1; i>=0; i--) for(j=sis.height()-1; j>=0; j--) for(k=sis.depth()-1; k>=0; k--) sis.gene(i,j,k, (GARandomBit() ? mom.gene(i,j,k):dad.gene(i,j,k))); } else{ int minx = (mom.width() < dad.width()) ? mom.width() : dad.width(); int miny = (mom.height() < dad.height()) ? mom.height() : dad.height(); int minz = (mom.depth() < dad.depth()) ? mom.depth() : dad.depth(); minx = (sis.width() < minx) ? sis.width() : minx; miny = (sis.height() < miny) ? sis.height() : miny; minz = (sis.depth() < minz) ? sis.depth() : minz; for(i=minx-1; i>=0; i--) for(j=miny-1; j>=0; j--) for(k=minz-1; k>=0; k--) sis.gene(i,j,k, (GARandomBit() ? mom.gene(i,j,k):dad.gene(i,j,k))); } nc = 1; } return nc; }
int GA3DBinaryStringGenome::resize(int w, int h, int d) { if(w == (int)nx && h == (int)ny && d == (int)nz) return sz; if(w == GAGenome::ANY_SIZE) w = GARandomInt(minX, maxX); else if(w < 0) w = nx; // do nothing else if(minX == maxX) minX=maxX = w; else{ if(w < (int)minX) w=minX; if(w > (int)maxX) w=maxX; } if(h == GAGenome::ANY_SIZE) h = GARandomInt(minY, maxY); else if(h < 0) h = ny; // do nothing else if(minY == maxY) minY=maxY = h; else{ if(h < (int)minY) h=minY; if(h > (int)maxY) h=maxY; } if(d == GAGenome::ANY_SIZE) d = GARandomInt(minZ, maxZ); else if(d < 0) d = nz; // do nothing else if(minZ == maxZ) minZ=maxZ = d; else{ if(d < (int)minZ) d=minZ; if(d > (int)maxZ) d=maxZ; } if(w < (int)nx && h < (int)ny){ int z=GAMin((int)nz,d); for(int k=0; k<z; k++) for(int j=0; j<h; j++) GABinaryString::move(k*h*w+j*w,k*ny*nx+j*nx,w); } else if(w < (int)nx){ int z=GAMin((int)nz,d); for(int k=0; k<z; k++) for(int j=0; j<(int)ny; j++) GABinaryString::move(k*ny*w+j*w,k*ny*nx+j*nx,w); } else if(h < (int)ny){ int z=GAMin((int)nz,d); for(int k=0; k<z; k++) for(int j=0; j<h; j++) GABinaryString::move(k*h*nx+j*nx,k*ny*nx+j*nx,nx); } GABinaryString::resize(w*h*d); if(w > (int)nx && h > (int)ny){ // adjust the existing bits int z=GAMin((int)nz,d); for(int k=z-1; k>=0; k--){ int j; for(j=ny-1; j>=0; j--){ GABinaryString::move(k*h*w+j*w,k*ny*nx+j*nx,nx); for(int i=nx; i<w; i++) bit(k*h*w+j*w+i, GARandomBit()); } for(j=ny; j<h; j++) for(int i=0; i<w; i++) bit(k*h*w+j*w+i, GARandomBit()); } } else if(w > (int)nx){ int z=GAMin((int)nz,d); for(int k=z-1; k>=0; k--){ for(int j=h-1; j>=0; j--){ GABinaryString::move(k*h*w+j*w,k*h*nx+j*nx,nx); for(int i=nx; i<w; i++) bit(k*h*w+j*w+i, GARandomBit()); } } } else if(h > (int)ny){ int z=GAMin((int)nz,d); for(int k=z-1; k>=0; k--){ int j; for(j=ny-1; j>=0; j--) GABinaryString::move(k*h*w+j*w,k*ny*w+j*w,w); for(j=ny; j<h; j++) for(int i=0; i<w; i++) bit(k*h*w+j*w+i, GARandomBit()); } } if(d > (int)nz){ // change in depth is always new bits for(int i=w*h*nz; i<w*h*d; i++) bit(i, GARandomBit()); } nx = w; ny = h; nz = d; _evaluated = gaFalse; return sz; }
// Make sure our bitmask is big enough, generate a mask, then use it to // extract the information from each parent to stuff the two children. // We don't deallocate any space for the masks under the assumption that we'll // have to use them again in the future. // For now we'll implement this only for fixed length genomes. If you use // this crossover method on genomes of different sizes it might break! int GA3DBinaryStringGenome:: UniformCrossover(const GAGenome& p1, const GAGenome& p2, GAGenome* c1, GAGenome* c2){ GA3DBinaryStringGenome &mom=(GA3DBinaryStringGenome &)p1; GA3DBinaryStringGenome &dad=(GA3DBinaryStringGenome &)p2; int i,j,k, nc=0;; if(c1 && c2){ GA3DBinaryStringGenome &sis=(GA3DBinaryStringGenome &)*c1; GA3DBinaryStringGenome &bro=(GA3DBinaryStringGenome &)*c2; if(sis.width() == bro.width() && sis.height() == bro.height() && sis.depth() == bro.depth() && mom.width() == dad.width() && mom.height() == dad.height() && mom.depth() == dad.depth() && sis.width() == mom.width() && sis.height() == mom.height() && sis.depth() == mom.depth()){ for(i=sis.width()-1; i>=0; i--){ for(j=sis.height()-1; j>=0; j--){ for(k=sis.depth()-1; k>=0; k--){ if(GARandomBit()){ sis.gene(i,j,k, mom.gene(i,j,k)); bro.gene(i,j,k, dad.gene(i,j,k)); } else{ sis.gene(i,j,k, dad.gene(i,j,k)); bro.gene(i,j,k, mom.gene(i,j,k)); } } } } } else{ GAMask mask; int maxx = GAMax(sis.width(), bro.width()); int minx = GAMin(mom.width(), dad.width()); int maxy = GAMax(sis.height(), bro.height()); int miny = GAMin(mom.height(), dad.height()); int maxz = GAMax(sis.depth(), bro.depth()); int minz = GAMin(mom.depth(), dad.depth()); mask.size(maxx*maxy*maxz); for(i=0; i<maxx; i++) for(j=0; j<maxy; j++) for(k=0; k<maxz; k++) mask[i*maxy*maxz+j*maxz+k] = GARandomBit(); minx = GAMin(sis.width(), minx); miny = GAMin(sis.height(), miny); minz = GAMin(sis.depth(), minz); for(i=minx-1; i>=0; i--) for(j=miny-1; j>=0; j--) for(k=minz-1; k>=0; k--) sis.gene(i,j,k, (mask[i*miny*minz+j*minz+k] ? mom.gene(i,j,k) : dad.gene(i,j,k))); minx = GAMin(bro.width(), minx); miny = GAMin(bro.height(), miny); minz = GAMin(bro.depth(), minz); for(i=minx-1; i>=0; i--) for(j=miny-1; j>=0; j--) for(k=minz-1; k>=0; k--) bro.gene(i,j,k, (mask[i*miny*minz+j*minz+k] ? dad.gene(i,j,k) : mom.gene(i,j,k))); } nc = 2; } else if(c1 || c2){ GA3DBinaryStringGenome &sis = (c1 ? (GA3DBinaryStringGenome&)*c1 : (GA3DBinaryStringGenome&)*c2); if(mom.width() == dad.width() && mom.height() == dad.height() && mom.depth() == dad.depth() && sis.width() == mom.width() && sis.height() == mom.height() && sis.depth() == mom.depth()){ for(i=sis.width()-1; i>=0; i--) for(j=sis.height()-1; j>=0; j--) for(k=sis.depth()-1; k>=0; k--) sis.gene(i,j,k, (GARandomBit() ? mom.gene(i,j,k):dad.gene(i,j,k))); } else{ int minx = GAMin(mom.width(), dad.width()); int miny = GAMin(mom.height(), dad.height()); int minz = GAMin(mom.depth(), dad.depth()); minx = GAMin(sis.width(), minx); miny = GAMin(sis.height(), miny); minz = GAMin(sis.depth(), minz); for(i=minx-1; i>=0; i--) for(j=miny-1; j>=0; j--) for(k=minz-1; k>=0; k--) sis.gene(i,j,k, (GARandomBit() ? mom.gene(i,j,k):dad.gene(i,j,k))); } nc = 1; } return nc; }
// 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; }