SecondBitEA.cpp

00001 //-----------------------------------------------------------------------------
00002 // SecondGA.cpp
00003 //-----------------------------------------------------------------------------
00004 //*
00005 // Same code than FirstBitEA as far as Evolutionary Computation is concerned
00006 // but now you learn to enter the parameters in a more flexible way
00007 // and to twidle the output to your preferences!
00008 //-----------------------------------------------------------------------------
00009 #ifdef HAVE_CONFIG_H
00010 #include <config.h>
00011 #endif
00012 
00013 // standard includes
00014 #include <fstream>
00015 #include <iostream>   // cout
00016 #include <stdexcept>  // runtime_error
00017 
00018 // the general include for eo
00019 #include <eo>
00020 #include <ga.h>
00021 
00022 // Use functions from namespace std
00023 using namespace std;
00024 
00025 // EVAL
00026 #include "binary_value.h"
00027 
00028 // REPRESENTATION
00029 //-----------------------------------------------------------------------------
00030 // define your genotype and fitness types
00031 typedef eoBit<double> Indi;
00032 
00033 // the main_function: nothing changed(!), except variable initialization
00034 void main_function(int argc, char **argv)
00035 {
00036 // PARAMETRES
00037 //-----------------------------------------------------------------------------
00038 // instead of having all values of useful parameters as constants, read them:
00039 // either on the command line (--option=value or -o=value)
00040 //     or in a parameter file (same syntax, order independent,
00041 //                             # = usual comment character
00042 //     or in the environment (TODO)
00043 
00044   // First define a parser from the command-line arguments
00045     eoParser parser(argc, argv);
00046 
00047     // For each parameter, define Parameter, read it through the parser,
00048     // and assign the value to the variable
00049 
00050     eoValueParam<uint32_t> seedParam(time(0), "seed", "Random number seed", 'S');
00051     parser.processParam( seedParam );
00052     unsigned seed = seedParam.value();
00053 
00054    // description of genotype
00055     eoValueParam<unsigned int> vecSizeParam(8, "vecSize", "Genotype size",'V');
00056     parser.processParam( vecSizeParam, "Representation" );
00057     unsigned vecSize = vecSizeParam.value();
00058 
00059    // parameters for evolution engine
00060     eoValueParam<unsigned int> popSizeParam(10, "popSize", "Population size",'P');
00061     parser.processParam( popSizeParam, "Evolution engine" );
00062     unsigned popSize = popSizeParam.value();
00063 
00064     eoValueParam<unsigned int> tSizeParam(10, "tSize", "Tournament size",'T');
00065     parser.processParam( tSizeParam, "Evolution Engine" );
00066     unsigned tSize = tSizeParam.value();
00067 
00068    // init and stop
00069     eoValueParam<string> loadNameParam("", "Load","A save file to restart from",'L');
00070     parser.processParam( loadNameParam, "Persistence" );
00071     string loadName = loadNameParam.value();
00072 
00073     eoValueParam<unsigned int> maxGenParam(100, "maxGen", "Maximum number of generations",'G');
00074     parser.processParam( maxGenParam, "Stopping criterion" );
00075     unsigned maxGen = maxGenParam.value();
00076 
00077     eoValueParam<unsigned int> minGenParam(100, "minGen", "Minimum number of generations",'g');
00078     parser.processParam( minGenParam, "Stopping criterion" );
00079     unsigned minGen = minGenParam.value();
00080 
00081     eoValueParam<unsigned int> steadyGenParam(100, "steadyGen", "Number of generations with no improvement",'s');
00082     parser.processParam( steadyGenParam, "Stopping criterion" );
00083     unsigned steadyGen = steadyGenParam.value();
00084 
00085    // operators probabilities at the algorithm level
00086     eoValueParam<double> pCrossParam(0.6, "pCross", "Probability of Crossover", 'C');
00087     parser.processParam( pCrossParam, "Genetic Operators" );
00088     double pCross = pCrossParam.value();
00089 
00090     eoValueParam<double> pMutParam(0.1, "pMut", "Probability of Mutation", 'M');
00091     parser.processParam( pMutParam, "Genetic Operators" );
00092     double pMut = pMutParam.value();
00093 
00094    // relative rates for crossovers
00095     eoValueParam<double> onePointRateParam(1, "onePointRate", "Relative rate for one point crossover", '1');
00096     parser.processParam( onePointRateParam, "Genetic Operators" );
00097     double onePointRate = onePointRateParam.value();
00098 
00099     eoValueParam<double> twoPointsRateParam(1, "twoPointRate", "Relative rate for two point crossover", '2');
00100     parser.processParam( twoPointsRateParam, "Genetic Operators" );
00101     double twoPointsRate = twoPointsRateParam.value();
00102 
00103     eoValueParam<double> uRateParam(2, "uRate", "Relative rate for uniform crossover", 'U');
00104     parser.processParam( uRateParam, "Genetic Operators" );
00105     double URate =  uRateParam.value();
00106 
00107    // relative rates and private parameters for mutations;
00108     eoValueParam<double> pMutPerBitParam(0.01, "pMutPerBit", "Probability of flipping 1 bit in bit-flip mutation", 'b');
00109     parser.processParam( pMutPerBitParam, "Genetic Operators" );
00110     double pMutPerBit = pMutPerBitParam.value();
00111 
00112     eoValueParam<double> bitFlipRateParam(0.01, "bitFlipRate", "Relative rate for bit-flip mutation", 'B');
00113     parser.processParam( bitFlipRateParam, "Genetic Operators" );
00114     double bitFlipRate =  bitFlipRateParam.value();
00115 
00116     eoValueParam<double> oneBitRateParam(0.01, "oneBitRate", "Relative rate for deterministic bit-flip mutation", 'D');
00117     parser.processParam( oneBitRateParam, "Genetic Operators" );
00118     double oneBitRate = oneBitRateParam.value();
00119 
00120     // the name of the "status" file where all actual parameter values will be saved
00121     string str_status = parser.ProgramName() + ".status"; // default value
00122     eoValueParam<string> statusParam(str_status.c_str(), "status","Status file",'S');
00123     parser.processParam( statusParam, "Persistence" );
00124 
00125    // do the following AFTER ALL PARAMETERS HAVE BEEN PROCESSED
00126    // i.e. in case you need parameters somewhere else, postpone these
00127     if (parser.userNeedsHelp())
00128       {
00129         parser.printHelp(cout);
00130         exit(1);
00131       }
00132     if (statusParam.value() != "")
00133       {
00134         ofstream os(statusParam.value().c_str());
00135         os << parser;           // and you can use that file as parameter file
00136       }
00137 
00138 // EVAL
00140   // Fitness function
00142   // Evaluation: from a plain C++ fn to an EvalFunc Object ...
00143   eoEvalFuncPtr<Indi, double, const vector<bool>& > plainEval( binary_value );
00144   // ... to an object that counts the nb of actual evaluations
00145   eoEvalFuncCounter<Indi> eval(plainEval);
00146 
00147 // INIT
00149   // Initilisation of population
00151   // Either load or initialize
00152   // create an empty pop
00153   eoPop<Indi> pop;
00154   // create a state for reading
00155   eoState inState;              // a state for loading - WITHOUT the parser
00156   // register the rng and the pop in the state, so they can be loaded,
00157   // and the present run will be the exact conitnuation of the saved run
00158   // eventually with different parameters
00159   inState.registerObject(rng);
00160   inState.registerObject(pop);
00161 
00162   if (loadName != "")
00163     {
00164       inState.load(loadName); //  load the pop and the rng
00165       // the fitness is read in the file:
00166       // do only evaluate the pop if the fitness has changed
00167     }
00168   else
00169     {
00170       rng.reseed(seed);
00171       // a Indi random initializer
00172       // based on boolean_generator class (see utils/rnd_generator.h)
00173       eoUniformGenerator<bool> uGen;
00174       eoInitFixedLength<Indi> random(vecSize, uGen);
00175 
00176       // Init pop from the randomizer: need to use the append function
00177       pop.append(popSize, random);
00178       // and evaluate pop (STL syntax)
00179       apply<Indi>(eval, pop);
00180     } // end of initializatio of the population
00181 
00182 // OUTPUT
00183   // sort pop for pretty printout
00184   pop.sort();
00185   // Print (sorted) intial population (raw printout)
00186   cout << "Initial Population" << endl << pop << endl;
00187 
00188 // ENGINE
00190   // selection and replacement
00192 // SELECT
00193   // The robust tournament selection
00194   eoDetTournamentSelect<Indi> selectOne(tSize);       // tSize in [2,POPSIZE]
00195   // is now encapsulated in a eoSelectPerc (stands for Percentage)
00196   eoSelectPerc<Indi> select(selectOne);
00197 
00198 // REPLACE
00199   // And we now have the full slection/replacement - though with
00200   // the same generational replacement at the moment :-)
00201   eoGenerationalReplacement<Indi> replace;
00202 
00203 // OPERATORS
00205   // The variation operators
00207 // CROSSOVER
00208   // 1-point crossover for bitstring
00209   eo1PtBitXover<Indi> xover1;
00210   // uniform crossover for bitstring
00211   eoUBitXover<Indi> xoverU;
00212   // 2-pots xover
00213   eoNPtsBitXover<Indi> xover2(2);
00214   // Combine them with relative rates
00215   eoPropCombinedQuadOp<Indi> xover(xover1, onePointRate);
00216   xover.add(xoverU, URate);
00217   xover.add(xover2, twoPointsRate, true);
00218 
00219 // MUTATION
00220   // standard bit-flip mutation for bitstring
00221   eoBitMutation<Indi>  mutationBitFlip(pMutPerBit);
00222   // mutate exactly 1 bit per individual
00223   eoDetBitFlip<Indi> mutationOneBit;
00224   // Combine them with relative rates
00225   eoPropCombinedMonOp<Indi> mutation(mutationBitFlip, bitFlipRate);
00226   mutation.add(mutationOneBit, oneBitRate, true);
00227 
00228   // The operators are  encapsulated into an eoTRansform object
00229   eoSGATransform<Indi> transform(xover, pCross, mutation, pMut);
00230 
00231 // STOP
00233   // termination condition see FirstBitEA.cpp
00235   eoGenContinue<Indi> genCont(maxGen);
00236   eoSteadyFitContinue<Indi> steadyCont(minGen, steadyGen);
00237   eoFitContinue<Indi> fitCont(vecSize);
00238   eoCombinedContinue<Indi> continuator(genCont);
00239   continuator.add(steadyCont);
00240   continuator.add(fitCont);
00241 
00242 
00243 // CHECKPOINT
00244   // but now you want to make many different things every generation
00245   // (e.g. statistics, plots, ...).
00246   // the class eoCheckPoint is dedicated to just that:
00247 
00248   // Declare a checkpoint (from a continuator: an eoCheckPoint
00249   // IS AN eoContinue and will be called in the loop of all algorithms)
00250   eoCheckPoint<Indi> checkpoint(continuator);
00251 
00252     // Create a counter parameter
00253     eoValueParam<unsigned> generationCounter(0, "Gen.");
00254 
00255     // Create an incrementor (sub-class of eoUpdater). Note that the
00256     // parameter's value is passed by reference,
00257     // so every time the incrementer is updated (every generation),
00258     // the data in generationCounter will change.
00259     eoIncrementor<unsigned> increment(generationCounter.value());
00260 
00261     // Add it to the checkpoint,
00262     // so the counter is updated (here, incremented) every generation
00263     checkpoint.add(increment);
00264 
00265     // now some statistics on the population:
00266     // Best fitness in population
00267     eoBestFitnessStat<Indi> bestStat;
00268     // Second moment stats: average and stdev
00269     eoSecondMomentStats<Indi> SecondStat;
00270 
00271     // Add them to the checkpoint to get them called at the appropriate time
00272     checkpoint.add(bestStat);
00273     checkpoint.add(SecondStat);
00274 
00275     // The Stdout monitor will print parameters to the screen ...
00276     eoStdoutMonitor monitor(false);
00277 
00278     // when called by the checkpoint (i.e. at every generation)
00279     checkpoint.add(monitor);
00280 
00281     // the monitor will output a series of parameters: add them
00282     monitor.add(generationCounter);
00283     monitor.add(eval);          // because now eval is an eoEvalFuncCounter!
00284     monitor.add(bestStat);
00285     monitor.add(SecondStat);
00286 
00287     // A file monitor: will print parameters to ... a File, yes, you got it!
00288     eoFileMonitor fileMonitor("stats.xg", " ");
00289 
00290     // the checkpoint mechanism can handle multiple monitors
00291     checkpoint.add(fileMonitor);
00292 
00293     // the fileMonitor can monitor parameters, too, but you must tell it!
00294     fileMonitor.add(generationCounter);
00295     fileMonitor.add(bestStat);
00296     fileMonitor.add(SecondStat);
00297 
00298     // Last type of item the eoCheckpoint can handle: state savers:
00299     eoState outState;
00300     // Register the algorithm into the state (so it has something to save!!)
00301     outState.registerObject(parser);
00302     outState.registerObject(pop);
00303     outState.registerObject(rng);
00304 
00305     // and feed the state to state savers
00306     // save state every 100th  generation
00307     eoCountedStateSaver stateSaver1(20, outState, "generation");
00308     // save state every 1 seconds
00309     eoTimedStateSaver   stateSaver2(1, outState, "time");
00310 
00311     // Don't forget to add the two savers to the checkpoint
00312     checkpoint.add(stateSaver1);
00313     checkpoint.add(stateSaver2);
00314     // and that's it for the (control and) output
00315 
00316 // GENERATION
00318   // the algorithm
00320 
00321   // Easy EA requires
00322   // stopping criterion, eval, selection, transformation, replacement
00323   eoEasyEA<Indi> gga(checkpoint, eval, select, transform, replace);
00324 
00325   // Apply algo to pop - that's it!
00326   gga(pop);
00327 
00328 // OUTPUT
00329   // Print (sorted) intial population
00330   pop.sort();
00331   cout << "FINAL Population\n" << pop << endl;
00332 // GENERAL
00333 }
00334 
00335 // A main that catches the exceptions
00336 int main(int argc, char **argv)
00337 {
00338     try
00339     {
00340         main_function(argc, argv);
00341     }
00342     catch(exception& e)
00343     {
00344         cout << "Exception: " << e.what() << '\n';
00345     }
00346 
00347     return 1;
00348 }

Generated on Thu Apr 19 11:02:29 2007 for EO by  doxygen 1.4.7