// 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; }
// 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; }
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; } }