Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

Population.h

Go to the documentation of this file.
00001 
00021 /*
00022  * GALib v2.0- A simple C++ library for Genetic Algorithms
00023  * Arthur van Dam <dam@math.uu.nl>
00024  * $Id: Population.h 441 2007-11-15 16:55:50Z adam $
00025  */
00026 #ifndef __GAL_POPULATION_H
00027 #define __GAL_POPULATION_H
00028 
00029 #include <iostream>
00030 #include <fstream>
00031 #include <vector>
00032 #include <string>
00033 #include <map>
00034 #include <algorithm>
00035 #include "Util.h"
00036 #include "Chromosome.h"
00037 #include "Problem.h"
00038 
00039 #define DOUBLE_MAX 1.7E+308
00040 namespace gal {
00041 
00054     template <class T> class Population {
00055     private:
00056         Problem<T>* _problem;                   /* problem with obj. func. and Chromosome constructors */
00057         std::vector<Chromosome<T>* > _members;  /* population members */
00058         std::vector<double> _objvalues;         /* Cached objective values of curr. generation */       
00059         std::vector<double> _fitnesses;         /* Cached fitness values of curr. generation */
00060         double _totalFitness;                   /* Cached total fitness of curr. generation */
00061         std::vector<int> _currentElite;         /* Cached indices of members that are elite in curr. generation */
00062         int _nrMem;                             /* Nr of members currently in population (during build-up of _members) */
00063         int _nrElite;                           /* Nr of elite members allowed */
00064         double _probMutate;                     /* Probability of mutation, for each bit */
00065         double _probCrossover;                  /* Probability of crossover, for two selected parents */
00066         int _objmaxindex;                       /* Index of maximum of the objective values */
00067         int _objminindex;                       /* Index of minimum of the objective values */
00068         double _objavg;                         /* Average of the objective values */
00069         double _prevmax;                        /* Maximum in previous step */
00070         double _overallmax;                     /* Maximum in all previous generations */
00071         double _nrequalmax;                     /* Number of equal maxima */
00072     /*
00073      * Constructors
00074      */
00075     public:
00082         Population(Problem<T>* problem) : _problem(problem), _members(),
00083                 _nrElite(0), _probMutate(0.0), _probCrossover(0.0) {}
00084 
00094         Population(Problem<T>* problem,
00095                 int size, int chromoLength) : _problem(problem), _members(),
00096                 _nrElite(0), _probMutate(0.0), _probCrossover(0.0)
00097         {
00098             initialise(size, chromoLength);
00099         }
00100 
00104         ~Population()
00105         {
00106             typename std::vector<Chromosome<T>* >::iterator it;
00107 
00108             for (it = _members.begin(); it != _members.end(); ++it) {
00109                 _problem->deleteChromosome(*it);
00110             }
00111         }
00112 
00113     public:
00119         void addMember(Chromosome<T>* g)
00120         {
00121             _members[_nrMem] = g;
00122             _objvalues[_nrMem] = 0.0;
00123             _fitnesses[_nrMem] = 0.0;
00124             _nrMem++;
00125         }
00126 
00130         int const size()
00131         {
00132             return _nrMem;
00133             // Should always be equal to _members.size(),
00134             // since only during initialisation, _members is being filled.
00135         }
00136 
00143         void initialise(int size, int chromoLength)
00144         {
00145             Chromosome<T>* tmpChr;
00146 
00147             _members.clear();
00148             _members.resize(size);
00149             _objvalues.resize(size);
00150             _fitnesses.resize(size);
00151             _nrMem = 0;
00152             for (int i = 0; i < size; ++i) {
00153                 tmpChr = _problem->constructChromosome(chromoLength);
00154                 addMember(tmpChr);
00155             }
00156             _prevmax=-1E+100;
00157             _overallmax=-1E+100;
00158             _nrequalmax=0;
00159             _objmaxindex=0;
00160             _objvalues[_objmaxindex] = _overallmax;
00161             evaluateFitness();
00162             
00163         }
00164 
00169         void setEliteSize(int nrElite)
00170         {
00171             _nrElite = nrElite > 0 ? nrElite : 0;
00172         }
00173 
00185         void setProbabilities(double probMutate, double probCrossover)
00186         {
00187             _probMutate = probMutate;
00188             _probCrossover = probCrossover;
00189         }
00190 
00191     public:
00199         void evaluateFitness()
00200         {
00201             /* Scale objective values between nmin and nmax
00202                before normalising */
00203             double a, b;
00204             a = 1.0;
00205             b = 10.0;
00206 
00207 
00208             /*** For all member chromosomes, determine objective value,
00209                  scale them between a and b.
00210                  
00211                  Later, maintain some stats for use in PRINTBEST, etc. printmodes.
00212             ***/
00213             /* Directly re-mark the elite members with the updated fitness values */
00214             markElite();
00215         }
00216 
00222         void markElite()
00223         {
00224             int i, imax;
00225             double maxfit;
00226             std::map<int, double> fitnessbackup;
00227             std::map<int, double>::iterator it;
00228 
00229             /*** After the fitness values have been updated, the old elite
00230                  has to be discarded and new elite members have to be selected.
00231                  The nr of elite members is available in the member
00232                  variable _nrElite, and the indices of elite members can be
00233                  stored in _currentElite.
00234             ***/
00235 
00236         }
00237 
00238     public:
00244         void mutate()
00245         {
00246             typename std::vector<Chromosome<T>* >::iterator it;
00247 
00248             /***
00249             Implement mutation of all member chromosomes yourself.
00250             ***/
00251         }
00252 
00260         int selectByRoulette()
00261         {
00262 
00263             /*** Select a (not yet selected) chromosome in the population
00264                  using the roulette wheel approach.
00265                  Hint: selection is based on fitness, but prevent that an
00266                  already selected chromosome is selected again.
00267              ***/
00268             return _members.front(); // dummy
00269         }
00270 
00278         void selectAndReproduce()
00279         {
00280             typename std::vector<Chromosome<T>* >::iterator it;
00281             int i, isel, nrParents, countElite, countNext;
00282             double tresh, sumFitness;
00283             std::vector<Chromosome<T>* > nextgen; // Create the complete new generation in here
00284             Chromosome<T>* sel;                   // The selected member by roulette wheel
00285             Chromosome<T>* child1;                // created children by crossover
00286             Chromosome<T>* child2;
00287             Chromosome<T>** parents = new Chromosome<T>*[2]; // small array with pointers to the two parents.
00288             std::vector<int>::iterator eliteAt, tmpAt;        // position of selected elite member in _currentElite array.
00289 
00290 
00291 
00292 
00293 
00294 
00295 
00296             nextgen.resize(size());
00297             countNext = 0;
00298             countElite = 0;
00299             // Start selection, and crossover with selected parents.
00300             while (countNext < size()) {
00301                 nrParents = 0;
00302                 // Select members until 2 members are allowed to be parents.
00303                 // First select all elite members (if any) as first parent in each couple
00304                 while (nrParents < 2 && countNext < size()) {
00305 
00306                     /*** Use roulette wheel selection to select a member for
00307                          the next generation and add it to the new population ***/
00308 
00309                     /*** For the just selected member, determine if it's
00310                          allowed to be a parent ***/
00311                 }
00312 
00313                 // If next generation is not yet full, produce two children by crossover
00314                 if (nrParents == 2 && countNext < size()-1) {
00315 
00316                     /*** two parents are known, produce two children
00317                          and add them to next generation. ***/
00318                     /*** HINT: Initialise children as literal copies of their parents,
00319                          (see Propblem::copyChromosome) then determine the crossover
00320                          points, and finally use Chromosome::crossover
00321                          (implement that one yourself). ***/
00322                          
00323                 } else {
00324 #ifdef __GAL_DEBUG
00325                     std::cout << "Next generation is full, discard children." << std::endl;
00326 #endif /* __GAL_DEBUG */
00327                 }
00328             }
00329             delete [] parents;
00330 
00331 
00332             /*** Don't forget to free up memory (with delete) of the chromosomes
00333                  that did not make it into the next generation. ***/
00334 
00335             // The new generation is now ready:
00336             _members = nextgen;
00337         }
00338 
00345         void nextGeneration()
00346         {
00347 
00348             /*** selectAndReproduce(); ***/
00349 
00350 
00351 
00352 
00353             mutate();
00354             
00355             evaluateFitness();
00356         }
00357 
00358     public:
00359     
00360     #define PRINTINTERP 1
00361     #define PRINTBITSTRING 2
00362     #define PRINTVALUE 4
00363     #define PRINTOBJECTIVE 8
00364     #define PRINTFITNESS 16
00365     
00366     #define PRINTALL 1
00367     #define PRINTBEST 2
00368     #define PRINTWORST 4
00369     #define PRINTAVG 8
00370     #define ONLYIFBETTER 16 
00371 
00388         void const print(int generationNr, int printbits, int printmode, std::ostream& outstr)
00389         {
00390             typename std::vector<Chromosome<T>* >::iterator it;
00391             int i = 0;
00392             int index;
00393 
00394             if (printmode & ONLYIFBETTER) {
00395                 if(_overallmax >= _objvalues[_objmaxindex]) {
00396                     return;
00397                 }
00398             }
00399 
00400             outstr.precision(12);
00401             if(printmode&PRINTALL) {
00402                 for (it = _members.begin(); it != _members.end(); ++it) 
00403                 {
00404                     if(generationNr>=0)
00405                         outstr << generationNr+1 << "\t";
00406                     if(printbits & PRINTINTERP)
00407                         outstr << (*it)->getInterpretedBitstringText() << "\t";
00408                     if(printbits & PRINTBITSTRING)
00409                     {   
00410                         outstr <<  (*it)->getBitstringText() << "\t";
00411                         /*if ((*it)->isElite())
00412                             outstr << "*";*/
00413                     }
00414                     if(printbits & PRINTVALUE)  
00415                         outstr <<(*it)->getValueText() << "\t";
00416                     if (printbits & PRINTOBJECTIVE) 
00417                         outstr << _objvalues[i] << "\t";
00418                     if (printbits & PRINTFITNESS) 
00419                         outstr << "Fit: " << _fitnesses[i] << "\t";
00420                     outstr << std::endl;
00421                     i++;
00422                 }
00423             }
00424             else if(printmode&PRINTAVG)
00425             {
00426                 if(generationNr>=0)
00427                     outstr << generationNr+1 << "\t";
00428                 if(printbits & PRINTOBJECTIVE)
00429                     outstr << _objavg << std::endl;
00430                 if(printbits & ( PRINTINTERP | PRINTBITSTRING | PRINTVALUE | PRINTFITNESS))
00431                     outstr << "Options make no sense voor print-average" << std::endl;
00432 
00433             }
00434             else 
00435             {
00436                 if(printmode & PRINTWORST)
00437                 {
00438                         outstr << "TODO ";
00439                         index=_objmaxindex; /* Should become objminindex later */
00440                 }
00441                 else if(printmode & PRINTBEST)  
00442                         index=_objmaxindex;
00443     
00444                 it = _members.begin();
00445                 it += index;
00446                 
00447                 if(generationNr>=0)
00448                     outstr << generationNr+1 << "\t";
00449                 if (printbits & PRINTOBJECTIVE) 
00450                     outstr << _objvalues[index] << "\t";
00451                 if(printbits & PRINTBITSTRING)
00452                     outstr <<  (*it)->getBitstringText() << "\t";
00453                 outstr << std::endl;
00454                     
00455             }   
00456         }
00457         
00466         int testConvergence(int nrequal)
00467         {
00468             double objmax = _objvalues[_objmaxindex];
00469             
00470             if(objmax==_prevmax)
00471                 _nrequalmax++;
00472             else
00473                 _nrequalmax=0;
00474 
00475             if(_nrequalmax==nrequal)
00476                 return 1;
00477             else
00478                 return 0;
00479                         
00480         }
00481 
00489         void writePopulation(std::ostream& outstr)
00490         {
00491             typename std::vector<Chromosome<T>* >::iterator it;
00492             int i;
00493 
00494             outstr << "# Bitstring\tElite?\tValue\tObj.value" << std::endl;
00495 
00496             i = 0;
00497             for (it = _members.begin(); it != _members.end(); ++it) 
00498             {
00499                 outstr <<  (*it)->getBitstringText();
00500                 outstr << "\t"; // Always delimit potential elite-'*'
00501                 if ((*it)->isElite())
00502                     outstr << "*";
00503                 outstr << "\t" << (*it)->getValueText();
00504                 outstr << "\t" << _objvalues[i];
00505                 outstr << std::endl;
00506                 i++;
00507             }
00508         }
00509 
00510 
00511 
00512 
00513 
00524         void readPopulation(std::istream& instr)
00525         {
00526             int chromoLength;
00527             Chromosome<T>* tmpChr;
00528 
00529             if (size() == 0 || (chromoLength = _members[0]->length()) == 0) {
00530                 std::cerr << "** Unexpected population size or bitlength! Is Population unitialised?" << std::endl;
00531                 return;
00532             }
00533 
00534             char chromoString[5*chromoLength];
00535             char c;
00536 
00537             int err = 0; // error during reading?
00538             int i;
00539 
00540             // Ignore first header line
00541             instr.ignore (1000000, '\n');
00542             if (instr.peek() == '\r') instr.ignore (1);
00543 
00544             i = 0;
00545             while (i < size() && !instr.eof()) {
00546                 instr.getline(chromoString, 1000000, '\t');
00547                 std::cout << "just read: \"" << chromoString << "\"" << std::endl;
00548                 tmpChr = _problem->copyChromosome(_members[i]); // Copying is just to get correct bitstring length.
00549                 tmpChr->setBits(chromoString);
00550 
00551                 // set elite status to true or false.
00552                 c = instr.peek();
00553                 if (c == '*') {
00554                     tmpChr->setElite(true);
00555                 } else if (c == '\t') {
00556                     tmpChr->setElite(false);
00557                 } else {
00558                     std::cerr << "** Unexpected character '" << c << "' (" << (int)c << ") at line " << (i+2) << ", pos. " << (chromoLength+1) << "." << std::endl;
00559                     std::cerr << "   Are bitstrings in file longer than current bitstrings?" << std::endl;
00560                     err = 1;
00561                     break;
00562                 }
00563 
00564                 delete _members[i];   // Clean up memory of current chromosome pointer.
00565                 _members[i] = tmpChr; // Place new chromosome in population
00566 
00567                 instr.ignore (1000000, '\n');
00568                 if (instr.peek() == '\r') instr.ignore (1);
00569 
00570                 i++;
00571             }
00572             
00573             if (i != size()) {
00574                 std::cerr << "** File was smaller than population." << std::endl;
00575                 err = 1;
00576             }
00577 
00578             if (!instr.eof()) {
00579                 std::cerr << "** File was larger than population." << std::endl;
00580             }
00581             
00582             if (err) {
00583                 std::cerr << "** Exiting." << std::endl;
00584                 exit(1);
00585 
00586 
00587 
00588             }
00589             evaluateFitness();
00590         }
00591 
00592     };
00593 }
00594 #endif /* __GAL_POPULATION_H */

Generated on Tue Oct 20 12:59:20 2009 for LabSci GALib optimisation by genetic algorithms, student version by  doxygen 1.3.9.1