📄 exercise3.1.cpp
字号:
//-----------------------------------------------------------------------------// SecondBitGA.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!//-----------------------------------------------------------------------------#ifdef HAVE_CONFIG_H#include <config.h>#endif// standard includes#include <fstream>#include <iostream> // cout#include <stdexcept> // runtime_error// the general include for eo#include <eo>// EVAL#include "binary_value.h"// REPRESENTATION//-----------------------------------------------------------------------------// Include the corresponding file#include <ga.h> // bitstring representation & operators// define your genotype and fitness typestypedef eoBit<eoMinimizingFitness> Indi;using namespace std;// the main_function: nothing changed(!), except variable initializationvoid main_function(int argc, char **argv){// PARAMETRES//-----------------------------------------------------------------------------// 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) // First define a parser from the command-line arguments eoParser parser(argc, argv); // For each parameter, define Parameter, read it through the parser, // and assign the value to the variable eoValueParam<uint32_t> seedParam(time(0), "seed", "Random number seed", 'S'); parser.processParam( seedParam ); unsigned seed = seedParam.value(); // description of genotype eoValueParam<unsigned int> vecSizeParam(100, "vecSize", "Genotype size",'V'); parser.processParam( vecSizeParam, "Representation" ); unsigned vecSize = vecSizeParam.value(); // parameters for evolution engine eoValueParam<unsigned int> popSizeParam(100, "popSize", "Population size",'P'); parser.processParam( popSizeParam, "Evolution engine" ); unsigned popSize = popSizeParam.value(); eoValueParam<unsigned int> tSizeParam(10, "tSize", "Tournament size",'T'); parser.processParam( tSizeParam, "Evolution Engine" ); unsigned tSize = tSizeParam.value(); // init and stop eoValueParam<string> loadNameParam("", "Load","A save file to restart from",'L'); parser.processParam( loadNameParam, "Persistence" ); string loadName = loadNameParam.value(); eoValueParam<unsigned int> maxGenParam(500, "maxGen", "Maximum number of generations",'G'); parser.processParam( maxGenParam, "Stopping criterion" ); unsigned maxGen = maxGenParam.value(); eoValueParam<unsigned int> minGenParam(500, "minGen", "Minimum number of generations",'g'); parser.processParam( minGenParam, "Stopping criterion" ); unsigned minGen = minGenParam.value(); eoValueParam<unsigned int> steadyGenParam(100, "steadyGen", "Number of generations with no improvement",'s'); parser.processParam( steadyGenParam, "Stopping criterion" ); unsigned steadyGen = steadyGenParam.value(); // operators probabilities at the algorithm level eoValueParam<double> pCrossParam(0.6, "pCross", "Probability of Crossover", 'C'); parser.processParam( pCrossParam, "Genetic Operators" ); double pCross = pCrossParam.value(); eoValueParam<double> pMutParam(0.1, "pMut", "Probability of Mutation", 'M'); parser.processParam( pMutParam, "Genetic Operators" ); double pMut = pMutParam.value(); // relative rates for crossovers eoValueParam<double> onePointRateParam(1, "onePointRate", "Relative rate for one point crossover", '1'); parser.processParam( onePointRateParam, "Genetic Operators" ); double onePointRate = onePointRateParam.value(); eoValueParam<double> twoPointsRateParam(1, "twoPointRate", "Relative rate for two point crossover", '2'); parser.processParam( twoPointsRateParam, "Genetic Operators" ); double twoPointsRate = twoPointsRateParam.value(); eoValueParam<double> uRateParam(2, "uRate", "Relative rate for uniform crossover", 'U'); parser.processParam( uRateParam, "Genetic Operators" ); double URate = uRateParam.value(); // relative rates and private parameters for mutations; eoValueParam<double> pMutPerBitParam(0.01, "pMutPerBit", "Probability of flipping 1 bit in bit-flip mutation", 'b'); parser.processParam( pMutPerBitParam, "Genetic Operators" ); double pMutPerBit = pMutPerBitParam.value(); eoValueParam<double> bitFlipRateParam(0.01, "bitFlipRate", "Relative rate for bit-flip mutation", 'B'); parser.processParam( bitFlipRateParam, "Genetic Operators" ); double bitFlipRate = bitFlipRateParam.value(); eoValueParam<double> oneBitRateParam(0.01, "oneBitRate", "Relative rate for deterministic bit-flip mutation", 'D'); parser.processParam( oneBitRateParam, "Genetic Operators" ); double oneBitRate = oneBitRateParam.value(); // the name of the "status" file where all actual parameter values will be saved string str_status = parser.ProgramName() + ".status"; // default value eoValueParam<string> statusParam(str_status.c_str(), "status","Status file",'S'); parser.processParam( statusParam, "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 (statusParam.value() != "") { ofstream os(statusParam.value().c_str()); os << parser; // and you can use that file as parameter file }// EVAL ///////////////////////////// // 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);// INIT //////////////////////////////// // 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 (loadName != "") { inState.load(loadName); // 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) eoUniformGenerator<bool> uGen; eoInitFixedLength<Indi> random(vecSize, uGen); // 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// OUTPUT // sort pop for pretty printout // pop.sort(); // Print (sorted) intial population (raw printout) cout << "Initial Population" << endl << pop ; cout << "and best is " << pop.best_element() << "\n\n"; cout << "and worse is " << pop.worse_element() << "\n\n";// ENGINE ///////////////////////////////////// // selection and replacement ////////////////////////////////////// SELECT // The robust tournament selection eoDetTournamentSelect<Indi> selectOne(tSize); // tSize in [2,POPSIZE] // is now encapsulated in a eoSelectPerc (entage) eoSelectPerc<Indi> select(selectOne);// by default rate==1// REPLACE // And we now have the full slection/replacement - though with // generational replacement at the moment :-) eoGenerationalReplacement<Indi> replace; // want to add (weak) elitism? easy! // rename the eoGenerationalReplacement replace_main, // then encapsulate it in the elitist replacement // eoWeakElitistReplacement<Indi> replace(replace_main);// OPERATORS ////////////////////////////////////// // The variation operators //////////////////////////////////////// CROSSOVER // 1-point crossover for bitstring eo1PtBitXover<Indi> xover1; // uniform crossover for bitstring eoUBitXover<Indi> xoverU; // 2-pots xover eoNPtsBitXover<Indi> xover2(2); // Combine them with relative rates eoPropCombinedQuadOp<Indi> xover(xover1, onePointRate); xover.add(xoverU, URate); xover.add(xover2, twoPointsRate, true);// MUTATION // standard bit-flip mutation for bitstring eoBitMutation<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);// STOP ////////////////////////////////////// // termination condition see FirstBitEA.cpp ///////////////////////////////////// eoGenContinue<Indi> genCont(maxGen); eoSteadyFitContinue<Indi> steadyCont(minGen, steadyGen); // eoFitContinue<Indi> fitCont(vecSize); // remove if minimizing :-) eoCombinedContinue<Indi> continuator(genCont); continuator.add(steadyCont); // continuator.add(fitCont); // Ctrl C signal handling: don't know if that works in MSC ...#ifndef _MSC_VER eoCtrlCContinue<Indi> ctrlC; continuator.add(ctrlC);#endif// CHECKPOINT // 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; eoAverageStat<Indi> averageStat; // Second moment stats: average and stdev eoSecondMomentStats<Indi> SecondStat; // the Fitness Distance Correlation // need first an object to compute the distances eoQuadDistance<Indi> dist; // Hamming distance eoFDCStat<Indi> fdcStat(dist); // Add them to the checkpoint to get them called at the appropriate time checkpoint.add(bestStat); checkpoint.add(averageStat); checkpoint.add(SecondStat); checkpoint.add(fdcStat); // 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); monitor.add(fdcStat); // test de eoPopStat and/or eoSortedPopStat. // Dumps the whole pop every 10 gen. // eoSortedPopStat<Indi> popStat(10, "Dump of whole population");// eoPopStat<Indi> popStat(10, "Dump of whole population");// checkpoint.add(popStat);// monitor.add(popStat); // A file monitor: will print parameters to ... a File, yes, you got it! eoFileMonitor fileMonitor("stats.xg", " "); // the checkpoint mechanism can handle monitors checkpoint.add(fileMonitor); // the fileMonitor can monitor parameters, too, but you must tell it! fileMonitor.add(generationCounter); fileMonitor.add(bestStat); fileMonitor.add(SecondStat);#ifndef _MSC_VER // and an eoGnuplot1DMonitor will 1-print to a file, and 2- plot on screen eoGnuplot1DMonitor gnuMonitor("best_average.xg",minimizing_fitness<Indi>()); // the checkpoint mechanism can handle multiple monitors checkpoint.add(gnuMonitor); // the gnuMonitor can monitor parameters, too, but you must tell it! gnuMonitor.add(eval); gnuMonitor.add(bestStat); gnuMonitor.add(averageStat); // send a scaling command to gnuplot gnuMonitor.gnuplotCommand("set yrange [0:500]"); // a specific plot monitor for FDC // first into a file (it adds everything ti itself eoFDCFileSnapshot<Indi> fdcFileSnapshot(fdcStat); // then to a Gnuplot monitor eoGnuplot1DSnapshot fdcGnuplot(fdcFileSnapshot); // and of coruse add them to the checkPoint checkpoint.add(fdcFileSnapshot); checkpoint.add(fdcGnuplot); // want to see how the fitness is spread? eoScalarFitnessStat<Indi> fitStat; checkpoint.add(fitStat); // a gnuplot-based monitor for snapshots: needs a dir name // where to store the files eoGnuplot1DSnapshot fitSnapshot("Fitnesses"); // add any stat that is a vector<double> to it fitSnapshot.add(fitStat); // and of course add it to the checkpoint checkpoint.add(fitSnapshot);#endif // Last type of item the eoCheckpoint can handle: state savers: eoState outState; // Register the algorithm into the state (so it has something to save!!) outState.registerObject(rng); outState.registerObject(pop); // 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// GENERATION ///////////////////////////////////////// // 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);// OUTPUT // Print (sorted) intial population pop.sort(); cout << "FINAL Population\n" << pop << endl;// GENERAL}// A main that catches the exceptionsint main(int argc, char **argv){ try { main_function(argc, argv); } catch(exception& e) { cout << "Exception: " << e.what() << '\n'; } return 1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -