Back to Lesson 3 - Tutorial main page - Top-Down page - Bottom-up page - Programming hints - EO documentation

SecondBitEA.cpp

Click on the figure to see the corresponding code.
In the code, the colors are meaningfull
The actual code is in boldface and the comment in normal face.

For this particular program, as all new lines are concerned with program parameter input and information output, the font color for program-parameter-related sections will refer to the section where the parameters are used whereas the background color will remain blue.


//-----------------------------------------------------------------------------
// SecondGA.cpp
//-----------------------------------------------------------------------------
//*
// Same code than FirstBitEA as far as Evolutionary Computation is concerned
// but now you learn to enter the parameters in a more flexible way
// and to twidle the output to your preferences!
//-----------------------------------------------------------------------------
// standard includes
#include <stdexcept>  // runtime_error 
#include <iostream>   // cout
#include <strstream>  // ostrstream, istrstream
#include <fstream>
// the general include for eo
#include <eo>
// a simple fitness function that computes the number of ones of a bitstring
#include "binary_value.h"
//-----------------------------------------------------------------------------
// define your genotype and fitness types
typedef eoBin<double> Indi;
//-----------------------------------------------------------------------------
// instead of having all values of useful parameters as constants, read them:
// either on the command line (--option=value or -o=value)
//        or in a parameter file (same syntax, order independent, 
//                                    # = usual comment character 
//        or in the environment (TODO)
// note that the parameters are passed by reference so they can be updated
void read_param(eoParser & _parser, 
uint32 & _seed,
unsigned int & _vecSize,
unsigned int & _popSize,
unsigned int & _tSize,
double & _pCross,
double & _pMut,
string & _load_name,
unsigned int & _maxGen,
unsigned int & _minGen,
unsigned int & _steadyGen,
double & _onePointRate, 
double & _twoPointsRate, 
double & _uRate, 
double & _pMutPerBit, 
double & _bitFlipRate, 
double & _oneBitRate
)

     // For each parameter, define Parameters directly in the parser, 
     // and assign the value to the variable
    eoValueParam<uint32>& seedParam = _parser.createParam<uint32>(time(0), "seed", "Random number seed", 'S');
     _seed = seedParam.value();

     eoValueParam<unsigned int>& vecSizeParam = _parser.createParam<unsigned int>(8, "vecSize", "Genotype size",'V', "Representation");
     _vecSize = vecSizeParam.value();

     eoValueParam<unsigned int>& popSizeParam = _parser.createParam<unsigned int>(10, "popSize", "Population size",'P', "Evolution");
     _popSize = popSizeParam.value();
     eoValueParam<unsigned int>& tSizeParam = _parser.createParam<unsigned int>(10, "tSize", "Tournament size",'T', "Evolution");
     _tSize = tSizeParam.value();

    eoValueParam<string>& load_nameParam = _parser.createParam<string>("", "Load","A save file to restart from",'L', "Persistence");
     _load_name = load_nameParam.value();

     eoValueParam<unsigned int>& maxGenParam = _parser.createParam<unsigned int>(100, "maxGen", "Maximum number of generations",'G', "Stopping criterion");
     _maxGen = maxGenParam.value();
     eoValueParam<unsigned int>& minGenParam = _parser.createParam<unsigned int>(100, "minGen", "Minimum number of generations",'g', "Stopping criterion");
     _minGen = minGenParam.value();
     eoValueParam<unsigned int>& steadyGenParam = _parser.createParam<unsigned int>(100, "steadyGen", "Number of generations with no improvement",'s', "Stopping criterion");
     _steadyGen = steadyGenParam.value();

     eoValueParam<double>& pCrossParam = _parser.createParam<double>(0.6, "pCross", "Probability of Crossover", 'C', "Genetic Operators"); 
     _pCross = pCrossParam.value();
     eoValueParam<double>& pMutParam = _parser.createParam<double>(0.1, "pMut", "Probability of Mutation", 'M', "Genetic Operators");
     _pMut = pMutParam.value();
     eoValueParam<double>& onePointRateParam = _parser.createParam<double>(1, "onePointRate", "Relative rate for one point crossover", '1', "Genetic Operators");
     _onePointRate = onePointRateParam.value();
     eoValueParam<double>& twoPointsRateParam = _parser.createParam<double>(1, "twoPointRate", "Relative rate for two point crossover", '2', "Genetic Operators");
     _twoPointsRate = twoPointsRateParam.value();
     eoValueParam<double>& uRateParam = _parser.createParam<double>(2, "uRate", "Relative rate for uniform crossover", 'U', "Genetic Operators");
     _uRate =  uRateParam.value();
     eoValueParam<double>& pMutPerBitParam = _parser.createParam<double>(0.01, "pMutPerBit", "Probability of flipping 1 bit in bit-flip mutation", 'b', "Genetic Operators");
     _pMutPerBit = pMutPerBitParam.value();
     eoValueParam<double>& bitFlipRateParam = _parser.createParam<double>(0.01, "bitFlipRate", "Relative rate for bit-flip mutation", 'B', "Genetic Operators");
     _bitFlipRate =  bitFlipRateParam.value();
     eoValueParam<double>& oneBitRateParam = _parser.createParam<double>(0.01, "oneBitRate", "Relative rate for deterministic bit-flip mutation", 'D', "Genetic Operators");
         _oneBitRate = oneBitRateParam.value();

     // the name of the "status" file where all actual parameter values will be saved
     string str_status = _parser.ProgramName() + ".status";
     eoValueParam<string>& status_nameParam = _parser.createParam<string>(str_status.c_str(), "status","Status file",'S', "Persistence");
   // do the following AFTER ALL PARAMETERS HAVE BEEN PROCESSED
   // i.e. in case you need parameters somewhere else, postpone these
     if (_parser.userNeedsHelp())
         {
             _parser.printHelp(cout);
             exit(1);
         }
     if (status_nameParam.value() != "")
         {
ofstream os(status_nameParam.value().c_str());
os << _parser; // and you can use that file as parameter file
         }
}

// now the main_function: nothing changed, except input/output
void main_function(int argc, char **argv)
{
   uint32 seed;
   // decription of genotype
   unsigned int vecSize;
   // parameters for evolution engine
   unsigned int popSize;
   unsigned int tSize;
   // operators probabilities at the algorithm level
   double pCross;
   double pMut;
   // init and stop
   string load_name;
   unsigned int maxGen;
   unsigned int minGen;
   unsigned int steadyGen;
   // rates for crossovers
   double onePointRate;
   double twoPointsRate;
   double URate;
   // rates and private parameters for mutations;
   double pMutPerBit;
   double bitFlipRate;
   double oneBitRate;
   // define a parser from the command-line arguments
     eoParser parser(argc, argv);
   // Now read the parameters of the program
     read_param(argc, argv, seed, vecSize, popSize, tSize,
           pCross, pMut, load_name, maxGen, minGen, steadyGen,
           onePointRate, twoPointsRate, URate, 
           pMutPerBit, bitFlipRate, oneBitRate );
 /////////////////////////////
 // Fitness function
 ////////////////////////////
 // Evaluation: from a plain C++ fn to an EvalFunc Object ...
 eoEvalFuncPtr<Indi, double, const vector<bool>& > plainEval( binary_value );
// ... to an object that counts the nb of actual evaluations
 eoEvalFuncCounter<Indi> eval(plainEval);
 ////////////////////////////////
 // Initilisation of population
 ////////////////////////////////
 // Either load or initialize
 // create an empty pop
 eoPop<Indi> pop;
 // create a state for reading
 eoState inState; // a state for loading - WITHOUT the parser
// register the rng and the pop in the state, so they can be loaded,
 // and the present run will be the exact conitnuation of the saved run
 // eventually with different parameters
 inState.registerObject(rng);
 inState.registerObject(pop);

if (load_name != "")
     {
         inState.load(load_name); //  load the pop and the rng
        // the fitness is read in the file: 
        // do only evaluate the pop if the fitness has changed
     }
 else
     {
         rng.reseed(seed);
        // a Indi random initializer
        // based on boolean_generator class (see utils/rnd_generator.h)
         eoInitFixedLength<Indi, boolean_generator> 
random(vecSize, boolean_generator());
        // Init pop from the randomizer: need to use the append function
         pop.append(popSize, random); 
        // and evaluate pop (STL syntax) 
         apply<Indi>(eval, pop);
     } // end of initializatio of the population

 // sort pop for pretty printout
 pop.sort();
 // Print (sorted) intial population (raw printout)
 cout << "Initial Population" << endl << pop << endl;
 /////////////////////////////////////
 // selection and replacement
 ////////////////////////////////////
 // The robust tournament selection
 eoDetTournament<Indi> selectOne(tSize);           // tSize in [2,POPSIZE]
 // is now encapsulated in a eoSelectPerc (entage)
 eoSelectPerc<Indi> select(selectOne);// by default rate==1
 // And we now have the full slection/replacement - though with 
 // no replacement (== generational replacement) at the moment :-)
 eoNoReplacement<Indi> replace; 
 //////////////////////////////////////
 // The variation operators
 //////////////////////////////////////
 // 1-point crossover for bitstring
 eoBinCrossover<Indi> xover1;
 // uniform crossover for bitstring
 eoBinUxOver<Indi> xoverU;
 // 2-pots xover
 eoBinNxOver<Indi> xover2(2);
 // Combine them with relative rates
 eoPropCombinedQuadOp<Indi> xover(xover1, onePointRate);
 xover.add(xoverU, URate);
 xover.add(xover2, twoPointsRate, true);
 // standard bit-flip mutation for bitstring
 eoBinMutation<Indi>  mutationBitFlip(pMutPerBit);
 // mutate exactly 1 bit per individual
 eoDetBitFlip<Indi> mutationOneBit; 
 // Combine them with relative rates
 eoPropCombinedMonOp<Indi> mutation(mutationBitFlip, bitFlipRate);
 mutation.add(mutationOneBit, oneBitRate, true);
 // The operators are  encapsulated into an eoTRansform object
 eoSGATransform<Indi> transform(xover, pCross, mutation, pMut);
 //////////////////////////////////////
 // termination condition see FirstBitEA.cpp
 /////////////////////////////////////
 eoGenContinue<Indi> genCont(maxGen);
 eoSteadyFitContinue<Indi> steadyCont(minGen, steadyGen);
 eoFitContinue<Indi> fitCont(vecSize);
 eoCombinedContinue<Indi> continuator(genCont);
 continuator.add(steadyCont);
 continuator.add(fitCont);
 // but now you want to make many different things every generation 
 // (e.g. statistics, plots, ...).
 // the class eoCheckPoint is dedicated to just that:
 // Declare a checkpoint (from a continuator: an eoCheckPoint 
 // IS AN eoContinue and will be called in the loop of all algorithms)
 eoCheckPoint<Indi> checkpoint(continuator);

    // Create a counter parameter
     eoValueParam<unsigned> generationCounter(0, "Gen.");

    // Create an incrementor (sub-class of eoUpdater). Note that the 
     // parameter's value is passed by reference, 
     // so every time the incrementer is updated (every generation),
     // the data in generationCounter will change.
     eoIncrementor<unsigned> increment(generationCounter.value());
    // Add it to the checkpoint, 
     // so the counter is updated (here, incremented) every generation
     checkpoint.add(increment);
    // now some statistics on the population:
     // Best fitness in population
     eoBestFitnessStat<Indi> bestStat;
     // Second moment stats: average and stdev
     eoSecondMomentStats<Indi> SecondStat;
    // Add them to the checkpoint to get them called at the appropriate time
     checkpoint.add(bestStat);
     checkpoint.add(SecondStat);
     // The Stdout monitor will print parameters to the screen ...
     eoStdoutMonitor monitor(false);

     // when called by the checkpoint (i.e. at every generation)
     checkpoint.add(monitor);
     // the monitor will output a series of parameters: add them 
     monitor.add(generationCounter);
     monitor.add(eval); // because now eval is an eoEvalFuncCounter!
     monitor.add(bestStat);
     monitor.add(SecondStat);
     // A file monitor: will print parameters to ... a File, yes, you got it!
     eoFileMonitor fileMonitor("stats.xg", " ");

     // the checkpoint mechanism can handle multiple monitors
     checkpoint.add(fileMonitor);
     // the fileMonitor can monitor parameters, too, but you must tell it!
     fileMonitor.add(generationCounter);
     fileMonitor.add(bestStat);
     fileMonitor.add(SecondStat);
     // Last type of item the eoCheckpoint can handle: state savers:
     eoState outState;
     // Register the algorithm into the state
     outState.registerObject(parser);
     outState.registerObject(pop);
     outState.registerObject(rng);
     // and feed the state to state savers
    // save state every 100th  generation
     eoCountedStateSaver stateSaver1(100, outState, "generation"); 
     // save state every 1 seconds 
     eoTimedStateSaver    stateSaver2(1, outState, "time"); 
    // Don't forget to add the two savers to the checkpoint
     checkpoint.add(stateSaver1);
     checkpoint.add(stateSaver2);
     // and that's it for the (control and) output

 /////////////////////////////////////////
 // the algorithm
 ////////////////////////////////////////
 // Easy EA requires 
 // selection, transformation, eval, replacement, and stopping criterion
 eoEasyEA<Indi> gga(checkpoint, eval, select, transform, replace);
 // Apply algo to pop - that's it!
 gga(pop);
 // Print (sorted) final population
 pop.sort();
 cout << "FINAL Population\n" << pop << endl;
}
// A main that catches the exceptions
int main(int argc, char **argv)
{
#ifdef _MSC_VER
     int flag = _CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF);
       flag |= _CRTDBG_LEAK_CHECK_DF;
     _CrtSetDbgFlag(flag);
//    _CrtSetBreakAlloc(100);
#endif
     try
     {
             main_function(argc, argv);
     }
     catch(exception& e)
     {
             cout << "Exception: " << e.what() << '\n';
     }
     return 1;
}


Back to Lesson 3 - Tutorial main page - Top-Down page - Bottom-up page - Programming hints - EO documentation
Marc Schoenauer

Last modified: Sun Nov 26 09:31:04 2000