[galib] Threaded Evaluator
Paul Smith
phhs80 at gmail.com
Sat Sep 3 18:07:13 EDT 2011
Quite useful example, Glenn! Thank you very much indeed!
Paul
On Sat, Sep 3, 2011 at 7:51 PM, Glenn Sugden <headcrash at mac.com> wrote:
> Here's ex1.C with my threaded modifications (note that you should probably be: using a queue for
> some maximum number of threads (e.g., number of available cores - 1) instead of threading the
> entire population, as well as more thorough error checking - but that's an exercise left to the
> reader :-)
>
>
> /* ----------------------------------------------------------------------------
> ex1.C
> mbwall 28jul94
> Copyright (c) 1995-1996 Massachusetts Institute of Technology
>
> DESCRIPTION:
> Example program for the SimpleGA class and 2DBinaryStringGenome class.
> This program tries to fill the 2Dgenome with alternating 1s and 0s.
> This example uses the default crossover (single point), default mutator
> (uniform random bit flip), and default initializer (uniform random) for the
> 2D genome.
> Notice that one-point crossover is not necessarily the best kind of crossover
> to use if you want to generate a 'good' genome with this kind of objective
> function. But it does work.
> ---------------------------------------------------------------------------- */
> //vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
> //| Modifications for a threaded evaluator by Glenn Sugden, 2011-09-03 |
> //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>
> #include <ga/GASimpleGA.h> // we're going to use the simple GA
> #include <ga/GA2DBinStrGenome.h> // and the 2D binary string genome
> #include <ga/std_stream.h>
>
> #define cout STD_COUT
>
> //vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
>
> #include <assert.h>
> #include <pthread.h>
>
> extern void MyEvaluator( GAPopulation & p );
> static void *thread_function( void *parameters );
>
> //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>
> float Objective( GAGenome & ); // This is the declaration of our obj function.
> // The definition comes later in the file.
>
> int main( int argc, char **argv )
> {
> cout << "Example 1\n\n";
> cout << "This program tries to fill a 2DBinaryStringGenome with\n";
> cout << "alternating 1s and 0s using a SimpleGA\n\n";
> cout.flush();
>
> // 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 ( int ii = 1; ii < argc; ii++ )
> {
> if ( strcmp( argv[ii++], "seed" ) == 0 )
> {
> GARandomSeed( (unsigned int) atoi( argv[ii] ) );
> }
> }
>
> // Declare variables for the GA parameters and set them to some default values.
>
> int width = 10;
> int height = 5;
> int popsize = 30;
> int ngen = 400;
> float pmut = 0.001;
> float pcross = 0.9;
>
> // Now create the GA and run it. First we create a genome of the type that
> // we want to use in the GA. The ga doesn't operate on this genome in the
> // optimization - it just uses it to clone a population of genomes.
>
> GA2DBinaryStringGenome genome( width, height, Objective );
>
> // Now that we have the genome, we create the genetic algorithm and set
> // its parameters - number of generations, mutation probability, and crossover
> // probability. And finally we tell it to evolve itself.
>
> GASimpleGA ga( genome );
> ga.populationSize( popsize );
> ga.nGenerations( ngen );
> ga.pMutation( pmut );
> ga.pCrossover( pcross );
>
> //vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
>
> GAPopulation *pop = const_cast< GAPopulation * >( &ga.population());
>
> assert(pop);
>
> GAPopulation *newpop = pop->clone();
>
> assert(newpop);
>
> newpop->userData( ga.userData() );
>
> newpop->evaluator( MyEvaluator );
>
> ga.population( *newpop );
>
> //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>
> ga.evolve();
>
> // Now we print out the best genome that the GA found.
>
> cout << "The GA found:\n" << ga.statistics().bestIndividual() << "\n";
>
> // That's it!
>
> return 0;
> }
>
> //vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
>
> extern void MyEvaluator( GAPopulation & p )
> {
> pthread_attr_t thread_attr;
>
> pthread_t *threads = new pthread_t[p.size()];
>
> assert( threads );
>
> int rc = pthread_attr_init( &thread_attr );
>
> if ( rc )
> std::cerr << "Error #" << rc << " in pthread_attr_init." << std::endl;
>
> rc = pthread_attr_setdetachstate( &thread_attr, PTHREAD_CREATE_JOINABLE );
>
> if ( rc )
> std::cerr << "Error #" << rc << " in pthread_attr_setdetachstate." << std::endl;
>
> for ( int i = 0; i < p.size(); i++ )
> {
> void* parameters = &p.individual( i );
>
> rc = pthread_create( &threads[i], &thread_attr, thread_function, parameters );
>
> if ( rc )
> std::cerr << "Error #" << rc << " for individual: " << i << " in pthread_create." << std::endl;
> }
>
> for ( int i = 0; i < p.size(); i++ )
> {
> void* value_ptr;
>
> rc = pthread_join(threads[i], &value_ptr);
>
> if ( rc )
> std::cerr << "Error #" << rc << " for individual: " << i << " in pthread_join." << std::endl;
>
> assert(value_ptr == &p.individual( i )); // Sanity check...
> }
>
> delete[] threads;
> }
>
> static void *thread_function( void *parameters )
> {
> GAGenome* genome = (GAGenome*) parameters;
>
> genome->evaluate();
>
> pthread_exit( parameters );
>
> return (0); // To get rid of compiler warning.
> }
>
> //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>
> // This is the objective function. All it does is check for alternating 0s and
> // 1s. If the gene is odd and contains a 1, the fitness is incremented by 1.
> // If the gene is even and contains a 0, the fitness is incremented by 1. No
> // penalties are assigned.
> // We have to do the cast because a plain, generic GAGenome doesn't have
> // the members that a GA2DBinaryStringGenome has. And it's ok to cast it
> // because we know that we will only get GA2DBinaryStringGenomes and
> // nothing else.
>
> float Objective( GAGenome& g )
> {
> GA2DBinaryStringGenome & genome = (GA2DBinaryStringGenome &) g;
> float score = 0.0;
> int count = 0;
> for ( int i = 0; i < genome.width(); i++ )
> {
> for ( int j = 0; j < genome.height(); j++ )
> {
> if ( genome.gene( i, j ) == 0 && count % 2 == 0 )
> score += 1.0;
> if ( genome.gene( i, j ) == 1 && count % 2 != 0 )
> score += 1.0;
> count++;
> }
> }
>
> return score;
> }
>
> _______________________________________________
> galib mailing list
> galib at mit.edu
> http://mailman.mit.edu/mailman/listinfo/galib
>
More information about the galib
mailing list