# exercise3.1.cpp

    00001 //-----------------------------------------------------------------------------
    00002 // SecondBitGA.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
    00021 // EVAL
    00022 #include "binary_value.h"
    00023
    00024 // REPRESENTATION
    00025 //-----------------------------------------------------------------------------
    00026 // Include the corresponding file
    00027 #include <ga.h>          // bitstring representation & operators
    00028 // define your genotype and fitness types
    00029 typedef eoBit<eoMinimizingFitness> Indi;
    00030
    00031 using namespace std;
    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(100, "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(100, "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(500, "maxGen", "Maximum number of generations",'G');
    00074     parser.processParam( maxGenParam, "Stopping criterion" );
    00075     unsigned maxGen = maxGenParam.value();
    00076
    00077     eoValueParam<unsigned int> minGenParam(500, "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 ;
    00187   cout << "and best is " << pop.best_element() << "\n\n";
    00188   cout << "and worse is " << pop.worse_element() << "\n\n";
    00189 // ENGINE
    00191   // selection and replacement
    00193 // SELECT
    00194   // The robust tournament selection
    00195   eoDetTournamentSelect<Indi> selectOne(tSize);       // tSize in [2,POPSIZE]
    00196   // is now encapsulated in a eoSelectPerc (entage)
    00197   eoSelectPerc<Indi> select(selectOne);// by default rate==1
    00198
    00199 // REPLACE
    00200   // And we now have the full slection/replacement - though with
    00201   // generational replacement at the moment :-)
    00202   eoGenerationalReplacement<Indi> replace;
    00203   // want to add (weak) elitism? easy!
    00204   // rename the eoGenerationalReplacement replace_main,
    00205   // then encapsulate it in the elitist replacement
    00206   //  eoWeakElitistReplacement<Indi> replace(replace_main);
    00207
    00208 // OPERATORS
    00210   // The variation operators
    00212 // CROSSOVER
    00213   // 1-point crossover for bitstring
    00214   eo1PtBitXover<Indi> xover1;
    00215   // uniform crossover for bitstring
    00216   eoUBitXover<Indi> xoverU;
    00217   // 2-pots xover
    00218   eoNPtsBitXover<Indi> xover2(2);
    00219   // Combine them with relative rates
    00220   eoPropCombinedQuadOp<Indi> xover(xover1, onePointRate);
    00221   xover.add(xoverU, URate);
    00222   xover.add(xover2, twoPointsRate, true);
    00223
    00224 // MUTATION
    00225   // standard bit-flip mutation for bitstring
    00226   eoBitMutation<Indi>  mutationBitFlip(pMutPerBit);
    00227   // mutate exactly 1 bit per individual
    00228   eoDetBitFlip<Indi> mutationOneBit;
    00229   // Combine them with relative rates
    00230   eoPropCombinedMonOp<Indi> mutation(mutationBitFlip, bitFlipRate);
    00231   mutation.add(mutationOneBit, oneBitRate, true);
    00232
    00233   // The operators are  encapsulated into an eoTRansform object
    00234   eoSGATransform<Indi> transform(xover, pCross, mutation, pMut);
    00235
    00236 // STOP
    00238   // termination condition see FirstBitEA.cpp
    00240   eoGenContinue<Indi> genCont(maxGen);
    00241   eoSteadyFitContinue<Indi> steadyCont(minGen, steadyGen);
    00242   // eoFitContinue<Indi> fitCont(vecSize);   // remove if minimizing :-)
    00243   eoCombinedContinue<Indi> continuator(genCont);
    00244   continuator.add(steadyCont);
    00245   //  continuator.add(fitCont);
    00246   // Ctrl C signal handling: don't know if that works in MSC ...
    00247 #ifndef _MSC_VER
    00248   eoCtrlCContinue<Indi> ctrlC;
    00249   continuator.add(ctrlC);
    00250 #endif
    00251
    00252 // CHECKPOINT
    00253   // but now you want to make many different things every generation
    00254   // (e.g. statistics, plots, ...).
    00255   // the class eoCheckPoint is dedicated to just that:
    00256
    00257   // Declare a checkpoint (from a continuator: an eoCheckPoint
    00258   // IS AN eoContinue and will be called in the loop of all algorithms)
    00259   eoCheckPoint<Indi> checkpoint(continuator);
    00260
    00261     // Create a counter parameter
    00262     eoValueParam<unsigned> generationCounter(0, "Gen.");
    00263
    00264     // Create an incrementor (sub-class of eoUpdater). Note that the
    00265     // parameter's value is passed by reference,
    00266     // so every time the incrementer is updated (every generation),
    00267     // the data in generationCounter will change.
    00268     eoIncrementor<unsigned> increment(generationCounter.value());
    00269
    00270     // Add it to the checkpoint,
    00271     // so the counter is updated (here, incremented) every generation
    00272     checkpoint.add(increment);
    00273
    00274     // now some statistics on the population:
    00275     // Best fitness in population
    00276     eoBestFitnessStat<Indi> bestStat;
    00277     eoAverageStat<Indi> averageStat;
    00278     // Second moment stats: average and stdev
    00279     eoSecondMomentStats<Indi> SecondStat;
    00280     // the Fitness Distance Correlation
    00281     // need first an object to compute the distances
    00282     eoQuadDistance<Indi> dist;  // Hamming distance
    00283     eoFDCStat<Indi> fdcStat(dist);
    00284
    00285     // Add them to the checkpoint to get them called at the appropriate time
    00286     checkpoint.add(bestStat);
    00287     checkpoint.add(averageStat);
    00288     checkpoint.add(SecondStat);
    00289     checkpoint.add(fdcStat);
    00290
    00291     // The Stdout monitor will print parameters to the screen ...
    00292     eoStdoutMonitor monitor(false);
    00293
    00294     // when called by the checkpoint (i.e. at every generation)
    00295     checkpoint.add(monitor);
    00296
    00297     // the monitor will output a series of parameters: add them
    00298     monitor.add(generationCounter);
    00299     monitor.add(eval);          // because now eval is an eoEvalFuncCounter!
    00300     monitor.add(bestStat);
    00301     monitor.add(SecondStat);
    00302     monitor.add(fdcStat);
    00303
    00304     // test de eoPopStat and/or eoSortedPopStat.
    00305     // Dumps the whole pop every 10 gen.
    00306     //    eoSortedPopStat<Indi> popStat(10, "Dump of whole population");
    00307 //     eoPopStat<Indi> popStat(10, "Dump of whole population");
    00308 //     checkpoint.add(popStat);
    00309 //     monitor.add(popStat);
    00310
    00311     // A file monitor: will print parameters to ... a File, yes, you got it!
    00312     eoFileMonitor fileMonitor("stats.xg", " ");
    00313
    00314     // the checkpoint mechanism can handle monitors
    00315     checkpoint.add(fileMonitor);
    00316
    00317     // the fileMonitor can monitor parameters, too, but you must tell it!
    00318     fileMonitor.add(generationCounter);
    00319     fileMonitor.add(bestStat);
    00320     fileMonitor.add(SecondStat);
    00321
    00322 #ifndef _MSC_VER
    00323     // and an eoGnuplot1DMonitor will 1-print to a file, and 2- plot on screen
    00324     eoGnuplot1DMonitor gnuMonitor("best_average.xg",minimizing_fitness<Indi>());
    00325     // the checkpoint mechanism can handle multiple monitors
    00326     checkpoint.add(gnuMonitor);
    00327     // the gnuMonitor can monitor parameters, too, but you must tell it!
    00328     gnuMonitor.add(eval);
    00329     gnuMonitor.add(bestStat);
    00330     gnuMonitor.add(averageStat);
    00331
    00332     // send a scaling command to gnuplot
    00333     gnuMonitor.gnuplotCommand("set yrange [0:500]");
    00334
    00335     // a specific plot monitor for FDC
    00336     // first into a file (it adds everything ti itself
    00337     eoFDCFileSnapshot<Indi> fdcFileSnapshot(fdcStat);
    00338     // then to a Gnuplot monitor
    00339     eoGnuplot1DSnapshot fdcGnuplot(fdcFileSnapshot);
    00340     // and of coruse add them to the checkPoint
    00341     checkpoint.add(fdcFileSnapshot);
    00342     checkpoint.add(fdcGnuplot);
    00343
    00344     // want to see how the fitness is spread?
    00345     eoScalarFitnessStat<Indi> fitStat;
    00346     checkpoint.add(fitStat);
    00347     // a gnuplot-based monitor for snapshots: needs a dir name
    00348     // where to store the files
    00349     eoGnuplot1DSnapshot fitSnapshot("Fitnesses");
    00350     // add any stat that is a vector<double> to it
    00351     fitSnapshot.add(fitStat);
    00352     // and of course add it to the checkpoint
    00353     checkpoint.add(fitSnapshot);
    00354 #endif
    00355     // Last type of item the eoCheckpoint can handle: state savers:
    00356     eoState outState;
    00357     // Register the algorithm into the state (so it has something to save!!)
    00358     outState.registerObject(rng);
    00359     outState.registerObject(pop);
    00360
    00361     // and feed the state to state savers
    00362     // save state every 100th  generation
    00363     eoCountedStateSaver stateSaver1(100, outState, "generation");
    00364     // save state every 1 seconds
    00365     eoTimedStateSaver   stateSaver2(1, outState, "time");
    00366
    00367     // Don't forget to add the two savers to the checkpoint
    00368     checkpoint.add(stateSaver1);
    00369     checkpoint.add(stateSaver2);
    00370     // and that's it for the (control and) output
    00371
    00372 // GENERATION
    00374   // the algorithm
    00376
    00377   // Easy EA requires
    00378   // selection, transformation, eval, replacement, and stopping criterion
    00379   eoEasyEA<Indi> gga(checkpoint, eval, select, transform, replace);
    00380
    00381   // Apply algo to pop - that's it!
    00382   gga(pop);
    00383
    00384 // OUTPUT
    00385   // Print (sorted) intial population
    00386   pop.sort();
    00387   cout << "FINAL Population\n" << pop << endl;
    00388 // GENERAL
    00389 }
    00390
    00391 // A main that catches the exceptions
    00392 int main(int argc, char **argv)
    00393 {
    00394     try
    00395     {
    00396         main_function(argc, argv);
    00397     }
    00398     catch(exception& e)
    00399     {
    00400         cout << "Exception: " << e.what() << '\n';
    00401     }
    00402
    00403     return 1;
    00404 }