void* backgroundEvaluate(void* backgroundEvaluatorData ) { assert(backgroundEvaluatorData!=NULL); GAGenome* individual = ((BackgroundEvaluator*)backgroundEvaluatorData)->individual(); assert(individual); individual->evaluate( ); ((BackgroundEvaluator*)backgroundEvaluatorData)->finished(true); return (backgroundEvaluatorData); }
GAPopulation::GAPopulation(const GAGenome & c, unsigned int popsize) { csz = N = GA_POP_CHUNKSIZE; n = (popsize < 1 ? 1 : popsize); while(N < n) N += csz; rind = new GAGenome * [N]; sind = new GAGenome * [N]; for(unsigned int i=0; i<n; i++) rind[i] = c.clone(GAGenome::ATTRIBUTES); memcpy(sind, rind, N * sizeof(GAGenome*)); // indDiv = new float[N*N]; indDiv = 0; neval = 0; rawSum = rawAve = rawDev = rawVar = rawMax = rawMin = 0.0; fitSum = fitAve = fitDev = fitVar = fitMax = fitMin = 0.0; popDiv = -1.0; rsorted = ssorted = evaluated = gaFalse; scaled = statted = divved = selectready = gaFalse; sortorder = HIGH_IS_BEST; init = DefaultInitializer; eval = DefaultEvaluator; slct = new DEFAULT_SELECTOR; slct->assign(*this); sclscm = new DEFAULT_SCALING; evaldata = nullptr; ga = nullptr; }
// Receive the bits from the specified task. Stuff the genome with the data. // Returns a negative number if there was a transmission failure. int UnpackIndividual(GAGenome& g) { GA1DBinaryStringGenome& genome = (GA1DBinaryStringGenome&)g; int length = 0; float score = 0.0; static int nbits = 0; static int* bits = 0; int status = 0; status = pvm_upkint(&length, 1, 1); if(nbits < length){ nbits = length; delete [] bits; bits = new int [nbits]; } status = pvm_upkint(bits, length, 1); genome.length(length); // resize the genome genome = bits; // stuff it with the bits status = pvm_upkfloat(&score, 1, 1); // get the score from process g.score(score); // set the score on the genome return status; }
// Send the bits of the genome to the task that requested them. First we send // the number of bits, then we send the bits themselves. Note that we can // handle genomes of varying lengths with this setup. We also pack the score // and stuff that in as well (so that they don't have to do an eval at the // other end). If we did this as a member function we could save the hassle // of an extra copy of the bits... // Returns negative number (error code) if failure. int PackIndividual(GAGenome& g) { GA1DBinaryStringGenome& genome = (GA1DBinaryStringGenome&)g; static int* bits = 0; static int nbits = 0; int status = 0;; if(nbits < genome.length()){ nbits = genome.length(); delete [] bits; bits = new int [nbits]; } int length = genome.length(); for(int i=0; i<length; i++) bits[i] = genome.gene(i); status = pvm_pkint(&length, 1, 1); status = pvm_pkint(bits, length, 1); float score = g.score(); status = pvm_pkfloat(&score, 1, 1); return status; }
// When we create a GA, we stuff the parameters with the basics that will be // needed by most genetic algorithms - num generations, p convergence, etc. GAGeneticAlgorithm::GAGeneticAlgorithm(const GAGenome& g) : stats(), params() { pop = new GAPopulation(g, gaDefPopSize); pop->geneticAlgorithm(*this); ud = nullptr; cf = GAGeneticAlgorithm::DEFAULT_TERMINATOR; d_seed = gaDefSeed; params.add(gaNseed, gaSNseed, GAParameter::INT, &d_seed); minmax = gaDefMiniMaxi; params.add(gaNminimaxi, gaSNminimaxi, GAParameter::INT, &minmax); ngen = gaDefNumGen; params.add(gaNnGenerations, gaSNnGenerations, GAParameter::INT, &ngen); nconv = gaDefNConv; stats.nConvergence(nconv); params.add(gaNnConvergence, gaSNnConvergence, GAParameter::INT, &nconv); pconv = gaDefPConv; params.add(gaNpConvergence, gaSNpConvergence, GAParameter::FLOAT, &pconv); pcross = gaDefPCross; params.add(gaNpCrossover, gaSNpCrossover, GAParameter::FLOAT, &pcross); pmut = gaDefPMut; params.add(gaNpMutation, gaSNpMutation, GAParameter::FLOAT, &pmut); int psize = pop->size(); params.add(gaNpopulationSize, gaSNpopulationSize, GAParameter::INT, &psize); stats.scoreFrequency(gaDefScoreFrequency1); params.add(gaNscoreFrequency, gaSNscoreFrequency, GAParameter::INT, &gaDefScoreFrequency1); stats.flushFrequency(gaDefFlushFrequency); params.add(gaNflushFrequency, gaSNflushFrequency, GAParameter::INT, &gaDefFlushFrequency); stats.recordDiversity(gaDefDivFlag); params.add(gaNrecordDiversity, gaSNrecordDiversity, GAParameter::INT, &gaDefDivFlag); stats.scoreFilename(gaDefScoreFilename); params.add(gaNscoreFilename, gaSNscoreFilename, GAParameter::STRING, gaDefScoreFilename); stats.selectScores(gaDefSelectScores); params.add(gaNselectScores, gaSNselectScores, GAParameter::INT, &gaDefSelectScores); stats.nBestGenomes(g, gaDefNumBestGenomes); params.add(gaNnBestGenomes, gaSNnBestGenomes, GAParameter::INT, &gaDefNumBestGenomes); scross = g.sexual(); across = g.asexual(); }
// Receive the score and set it on the genome. int RecvGenomeScore(GAGenome& g) { int status = 0; float score = 0.0; status = pvm_upkfloat(&score, 1, 1); // get the score from process g.score(score); // set the score on the genome return status; }
// Send only the score of the genome to the specified task. int SendGenomeScore(GAGenome& g, int tid) { int status = 0; float score = g.score(); status = pvm_initsend(PvmDataDefault); status = pvm_pkfloat(&score, 1, 1); status = pvm_send(tid, MSG_GENOME_SCORE); return status; }
float objective(GAGenome & c) { GA2DBinaryStringGenome & genome = (GA2DBinaryStringGenome &)c; short **pattern = (short **)c.userData(); float value=0.0; for(int i=0; i<genome.width(); i++) for(int j=0; j<genome.height(); j++) value += (float)(genome.gene(i,j) == pattern[i][j]); return(value); }
/** * The objective is the distance */ float Objective(GAGenome & g) { double x1, y1, z1; double x2, y2, z2; GeneticExperience *experience = (GeneticExperience *)g.userData(); if (experience == NULL) { cout << "Score: unable to find the experience" << endl; return 0; } cout << "Scoring... " << flush; experience->updateSplines(g); VREPClient &vrep = experience->getVrep(); //Main Loop vrep.start(); x1 = vrep.readPositionTrackerX(); y1 = vrep.readPositionTrackerY(); z1 = vrep.readPositionTrackerZ(); for (double t=0; t<SIMULATION_TIME; t+=0.02) { //Display state //Do next step vrep.nextStep(); //Compute motors move primitive_step(vrep, experience->getSplines()); } x2 = vrep.readPositionTrackerX(); y2 = vrep.readPositionTrackerY(); z2 = vrep.readPositionTrackerZ(); //End simulation vrep.stop(); double score = sqrt(pow(x1-x2,2)+pow(y1-y2,2)+pow(z1-z2,2)); cout << score << endl; return score; }
float GAGenome::NoComparator(const GAGenome& c, const GAGenome&) { GAErr(GA_LOC, c.className(), "comparator", gaErrOpUndef); return -1.0; }
int GAGenome::NoMutator(GAGenome & c, float) { GAErr(GA_LOC, c.className(), "mutator", gaErrOpUndef); return 0; }
/// These are the default genome operators. /// None does anything - they just post an error message to let you know that no /// method has been defined. These are for the base class (which has no /// function by itself). void GAGenome::NoInitializer(GAGenome & c) { GAErr(GA_LOC, c.className(), "initializer", gaErrOpUndef); }
void GADCrowdingGA::step() { if(pop->size() == 0) return; GAGenome *child = pop->individual(0).clone(); GAList<int> indpool; for (int i=0; i<pop->size(); i++) indpool.insert(i); do { int *ip; indpool.warp(GARandomInt(0,indpool.size()-1)); // select mom ip=indpool.remove(); GAGenome *mom = &pop->individual(*ip); delete ip; indpool.warp(GARandomInt(0,indpool.size()-1)); // select dad ip=indpool.remove(); GAGenome *dad = &pop->individual(*ip); delete ip; stats.numsel += 2; // create child stats.numcro += (*scross)(*mom, *dad, child, 0); stats.nummut += child->mutate(pMutation()); stats.numeval += 1; double d1 = child->compare(*mom); // replace closest parent double d2 = child->compare(*dad); if (d1 < d2) { if (minmax == MINIMIZE) { if (child->score() < mom->score()) { mom->copy(*child); stats.numrep += 1; } } else { if (child->score() > mom->score()) { mom->copy(*child); stats.numrep += 1; } } } else { if (minmax == MINIMIZE) { if (child->score() < dad->score()) { dad->copy(*child); stats.numrep += 1; } } else { if (child->score() > dad->score()) { dad->copy(*child); stats.numrep += 1; } } } } while (indpool.size()>1); pop->evaluate(gaTrue); stats.update(*pop); delete child; }
void PetriDish::GAPDEvaluator( GAPopulation & pop ) { assert(pop.size() > 0); // Since this is a static method, get this population's associated PetriDish PetriDish* thisPetriDish = dynamic_cast<PetriDish*>(pop.geneticAlgorithm()); assert(thisPetriDish); #ifdef USING_GASIMPLEGA // A workaround for oldPop not copying our Evaluator to the next set of Genomes (as opposed to hacking GASimpleGA.C) if ( thisPetriDish->_oldPopInitialized == false ) { thisPetriDish->_oldPopInitialized = true; thisPetriDish->oldPop->initialize(); } #endif//USING_GASIMPLEGA // Use all of the available cores (as reported by the processor) for threads unsigned numberOfThreadsToUse; #if USE_BOOST numberOfThreadsToUse = boost::thread::hardware_concurrency(); #else//USE_BOOST numberOfThreadsToUse = (unsigned)sysconf( _SC_NPROCESSORS_ONLN ); int errorCode; #endif//USE_BOOST // Allocate an array of pointers for the threads, as well as the associated background information #if USE_BOOST boost::thread** backgroundThreads = new boost::thread*[numberOfThreadsToUse]; #else//USE_BOOST pthread_t* backgroundThreads = new pthread_t[numberOfThreadsToUse]; #endif//USE_BOOST assert( backgroundThreads ); memset( backgroundThreads, 0, numberOfThreadsToUse * sizeof( void* ) ); BackgroundEvaluator** backgroundEvaluators = new BackgroundEvaluator*[numberOfThreadsToUse]; assert( backgroundEvaluators ); memset( backgroundEvaluators, 0, numberOfThreadsToUse * sizeof( BackgroundEvaluator* ) ); #if DEBUG cout << "Evaluating new GAPopulation ( " << pop.size( ) << " )... ( using " << numberOfThreadsToUse << " threads )" << std::endl; #endif//DEBUG int completed = 0; int indIndex = 0; u_int32_t tIndex = 0U; #if DEBUG float highestScoreSoFar = 0.0f; float total = 0.0f; #endif//DEBUG // Loop until every population member has been evaluated. while ( completed < pop.size( ) && ( thisPetriDish->_interrupt == false ) ) { // If we still have members to evaluate, and there's a free thread open if ( ( indIndex < pop.size( ) ) && ( backgroundThreads[tIndex] == NULL ) ) { // If we haven't allocated space for the evaluator thread information if( backgroundEvaluators[tIndex] == NULL ) { backgroundEvaluators[tIndex] = new BackgroundEvaluator( &pop.individual( indIndex ), indIndex ); assert( backgroundEvaluators[tIndex] != NULL ); } else { assert(backgroundEvaluators[tIndex]->finished() == true); backgroundEvaluators[tIndex]->newIndividual( &pop.individual( indIndex ), indIndex); } #if DEBUG cout << "Starting individual #" << indIndex + 1 << " ( of " << pop.size( ) << " )" << std::endl; #endif//DEBUG // Kick off the thread #if USE_BOOST try { backgroundThreads[tIndex] = new boost::thread( boost::ref(*backgroundEvaluators[tIndex]) ); } catch(const std::exception& e) { cerr << "boost::thread exception: " << e.what() << std::endl; return; } #else//USE_BOOST errorCode = pthread_create(&backgroundThreads[tIndex], NULL, backgroundEvaluate, backgroundEvaluators[tIndex]); if (errorCode!=0) { cerr << "pthread_create: Error #"<< errorCode << " (" << strerror(errorCode) << ")" << std::endl; return; } #endif//USE_BOOST assert(backgroundThreads[tIndex]); indIndex++; } // Our cyclic thread index checks for the completion of a running thread tIndex = ( tIndex+1 ) % numberOfThreadsToUse; // A (possibly still running) thread exists... if ( backgroundThreads[tIndex] != NULL ) { assert( backgroundEvaluators[tIndex] != NULL ); // Check to see if it is finished if ( backgroundEvaluators[tIndex]->finished() ) { // The thread has finished. Gather some stats (if DEBUGging) and free the thread up for the next individual completed++; #if DEBUG GAGenome* genome = backgroundEvaluators[tIndex]->individual( ); float score = genome->score( ); total += score; cout << "Received results from individual #" << backgroundEvaluators[tIndex]->index( ) << " ( " << completed << " of " << pop.size( ) << " finished ): Score: " << genome->score( ) << " (" << total / (float)completed << " is average so far)" << std::endl; if ( score > highestScoreSoFar ) { cout << "Found new high score so far: ( " << score << " > " << highestScoreSoFar <<" )" << std::endl; highestScoreSoFar = score; } #endif//DEBUG #if USE_BOOST delete backgroundThreads[tIndex]; #else//USE_BOOST errorCode = pthread_join(backgroundThreads[tIndex], NULL); assert(errorCode==0); #endif//USE_BOOST backgroundThreads[tIndex] = NULL; } else { // If it hasn't finished yet, give up some main() thread processor time to the background evaluators #if USE_BOOST boost::thread::yield(); #else//USE_BOOST pthread_yield(); #endif//USE_BOOST } } } if ( thisPetriDish->_interrupt == true ) { cerr << "...evaluation interrupted!" << std::endl; thisPetriDish->terminator(InterruptTerminator); } #if DEBUG else { cout << "...finished evaluating this population." << std::endl; } #endif//DEBUG for ( tIndex = 0; tIndex < numberOfThreadsToUse; tIndex++ ) { if ( thisPetriDish->_interrupt == false ) { // Double (sanity) check that all of the threads have actually been processed assert( backgroundThreads[tIndex] == NULL ); if ( backgroundEvaluators[tIndex] != NULL ) // This can happen if all cores aren't used { assert( backgroundEvaluators[tIndex]->finished() == true ); } } else { // If the GA has been interrupted, try and clean up the background threads if ( backgroundThreads[tIndex] != NULL ) { #if USE_BOOST backgroundThreads[tIndex]->interrupt(); delete backgroundThreads[tIndex]; #else//USE_BOOST pthread_cancel(backgroundThreads[tIndex]); errorCode = pthread_join(backgroundThreads[tIndex], NULL); assert(errorCode==0); #endif//USE_BOOST backgroundThreads[tIndex] = NULL; } } if ( backgroundEvaluators[tIndex] != NULL ) // This can happen if all cores aren't used { delete backgroundEvaluators[tIndex]; backgroundEvaluators[tIndex] = NULL; } } // Free up the thread and background information arrays if (backgroundThreads) { delete[] backgroundThreads; backgroundThreads = NULL; } if (backgroundEvaluators) { delete[] backgroundEvaluators; backgroundEvaluators = NULL; } }