|
| ||||||||||||||||||||
|
Interface SpecificationRationaleAs you may expect, there’s more than one way of implementing this approach. I can think of two major ones, but I’m sure you could think of plenty more. Template BasedEssentially, you implement a template within a header file, and assume that the candidates provide the necessary functions.
Generic ClassUsing this approach, the GA class takes a virtual candidate which you need to extend for your own solution. I’m currently using the template approach, but I’m thinking of moving to this more robust approach.
InterfaceBoth interfaces are based on the solution that you wish to optimise. This is done via a candidate class, which we’ll define in the next page since we don’t need to know its specification to design the GA class. Skeleton GA TemplateThough the class should come with suitable default parameters, you may want to define a simple interface for passing new custom parameters. Also, depending on the type of your implementation, you may want to pass Candidate Id’s rather than pointers. This will be especially useful for parallel implementations. //=================================================================== // GeneticAlgorithm //=================================================================== template <class T> class GeneticAlgorithm { public: /** * Fetch a new candidate for the evaluation. * * @return A solution that needs to be evaluated. */ T * GetCandidate(); /** * After evaluation, pass back the fitness of a given candidate. * * @param candidate Pointer to the candicate which was just evaluated. * @param fitness Result of the evaluation procedure. */ void Report( T * candidate, const float fitness ); }; // class GeneticAlgorithm That’s pretty much all the functionality you need! Everything else is wrapped inside the class, as a black box. More complex implementations will still seem simple to the user. Generic ClassThis approach has the same type of interface as the template, but it uses virtual candidates. You’ll also need a factory, passed in the constructor. // Constructor needs a factory GeneticAlgorithm( const Factory& factory ); // Fetch a new candidate for the evaluation. Candidate * GetCandidate(); // After evaluation, pass back the fitness of a given candidate. void Report( Candidate * c, const float fitness ); Note that you will have to type cast the abstract candidates returned by GetCandidate to your own type. Server InteractionThe game can now run independently from the GA. You’ll run your environment simulation code in the main loop, and do the evolution within the agent’s ‘think’: void Agent::Think() { // evolve every minute if (level.time() - start_evolution > 60.0f) { // pass back the neural network to the GA ga.Report( nn, fitness ); // and fetch a new one nn = ga.GetCandidate(); // store the current time start_evolution = level.time(); // and reset fitness fitness = 0; } // code based on the candidate turn = nn->Simulate( getDist(left), getDist(right) ); // fitness evaluation fitness -= fabsf( turn ); if (Collision()) fitness -= 10.0f; } // Agent::Think() Naturally, you can do much more funky stuff just before reporting the fitness, such as saving the best individual, or asking the GA for the best solution after a while. The framework has been established Remember you can visit the Message Store to discuss this tutorial. There are already 4 replies in the thread, why not join in? Back to the Genetic Algorithms Warehouse.
|






