Lesson 3 - Lesson 5 - Main page - Algorithm-Based - Component-Based - Hints - EO documentation

User's guide: General - Bitstring - Real - ES - Programmer's guide: General - Memory management - Parameters

# Tutorial Lesson 4: ready-to-use fully operational EA

In this lesson, you will still use the same Evolutionary Algorithm. But this time you will have full control of all components from the command-line or a parameter file.
You can even use the algorithm decribed here without any other knowledge of EO, just by writing your fitness function as a plain C++ function.
Contents

- User's guide
  - Representation independent, useful for all applications
  - BitEA, the binary version, similar to previous lessons
  - RealEA, the basic real-valued version, not efficient - see by yourself!
  - RealEA, the self-adaptive Evolution Strategy, best choice for continuous optimization in EO today (December 2004)
- Programmer's guide: the ultimate purpose of this tutorial is to make you able to do your own experiments - and these these will likely fall outside the scope of the two ready-to-use programs above. You wil hence need to learn more about
  - Building libraries (in spite of the template problem)
  - Memory management: it is radically different that in the 3 previous lessons - though relying of course on the same objects. Note that eoPersistent objects and eoParam objects are handled by different mechanisms.

User's guide

As already said, the behavior of the algorithms will be exactly the same as the previous one as far as optimization is concerned. Only now you will be able to tune every component of the algorithms (except the type of genotype) using run-time parameters.
Also, as in previous lessons, most of the code is representation-independent, i.e. is the same for both the binary genotypes and the real-valued genotypes. This small user's guide reflects that, but you can go directly to the binary or the real parts if you wish.

Warning: this is a user guide, not a programming guide. In particular, the keywords of the parameters are not the names of the underlying classes (though they should be similar in most cases).

User's guide:Parameter input The way to input parameters has already be described in Lesson 3. To get a list of parameters, type the command with option --help (or -h): with both testBit and testReal this will result in

- Printing the list of keywords on the standard output
- Creating (or overwriting) a file name testBit.status or testReal.status that contains the list of all recognized parameters and has the format of an input parameter file.

User's guide:The status file
This file will always contain the list of the parameters that have been actually used by the last run of the program, however thay have been entered (try `testBit -G1` and take a look a the status file). The parameters that are commented out (a # character comments out the rest of the line) in the file are those that were not specified by the user.
On the status file, the parameters are organized in sections. Note, however, that this format is not mandatory in the param file, as only the keywords are processed.

User's guide:Representation-independent parameters
In what follows, the fixed font colored text is directly taken from the status file and is commented between the lines. The presentation follows the status file format - only two sections are representation-dependent (see the corresponding binary or real sections). All other sections are presented now:

Section `###### General ######`
`# --help=0 # -h : Prints this message`
Boolean parameter of absolutely no interest: tells whether or not help was requested.

`# --seed=988700289 # -S : Random number seed`
Unsigned long parameter: the seed for the Random Number Generator If the parameter is absent, then time(0) is used, which indicates the number of seconds since Jan. 1 1980, is used ... and stored in the status file, of course, so you can repeat the same run by simply assigning that value again. There is no default value ("true" random seed).

Section `###### engine ######`
In this section, one chooses all components of the Evolution Engine (selection, replacemenet and the like).

`# --popSize=20 # -P : Population Size`
Integer parameter: the size of the population (constant along evolution). And yes, this is a representation independent parameter, as the population is created either from a file or using an eoInit object - and only that object is representation-dependent.
`# --selection=DetTour(2) # -S : Selection: Roulette, DetTour(T), StochTour(t) or Sequential(ordered/unordered)`
String parameter: Name of selection procedure. Availabable are the roulette wheel (name `Roulette`, fitness scaling coming soon); deterministic tournament (name `DetTour` with size - integer > 2 - in parentheses right after the name, use double quotes on the command line); stochastic tournament (name `StochTour` with probability - float in [0.5, 1] - in parentheses); sequential (name `Sequential`, all individuals in turn), either from best to worst (option `ordered` in parentheses), or in random ordered (option `unordered`); and finally repeated independent uniform choices (name `Random`). Default is DetTour(2).

`# --nbOffspring=100% # -O : Nb of offspring (percentage or absolute)`
Integer or real-valued parameter: this parameter indicates the amount of offspring that will be generated from the genitors every generation. However, this amount can be specified either relative to the population size, and it should then end with percent character (%), or as an absolute integer number (without the percent char).
Indeed, you can either want, say 7 times more offspring than parents (a rather common situation in Evolution Strategies), in which case you give value 700% to `nbOffspring` parameter; or you might want a single offspring whatever the population size, like in Steady-State evolution engines, in which case you simply enter value 1. Default is 100%.

`# --replacement=Comma # -R : Replacement: Comma, Plus, EPTour(T), SSGAWorst, SSGADet(T), SSGAStoch(t)`
String parameter: Name of replacement procedure. Availabable are the ES plus and comma deterministic replacement strategies (named respectively `Plus` and `Comma`); EP stochastic tournament (name `EPTour` with tournament size in parentheses); and the steady-state replacement procedures, at the moment only based on fitnesses, replacement being either deterministic (new born replace worst parent, name `SSGAWorst`), or based on a tournament (name `SSGADet` for deterministic tournament, size in parentheses, and `SSGAStoch` for stochastic tournament, probability in parentheses). Default is Comma (which btw is also SGA generational replacement whenever there are as many offspring as parents).

`# --weakElitism=0 # -w : Old best parent replaces new worst offspring *if necessary*`
Boolean parameter: if true, weak elitism is added to the replacement procedure (i.e. if the best fitness among the offspring is less than the best fitness, the best parent replaces the worst offspring). Default is false.

Section `###### Output ######`
This first section on Output contains parameters related to screen text output.

`# --useEval=1 # Use nb of eval. as counter (vs nb of gen.)`
Boolean parameter: whether or not you want the nb of evluations to be displayed and used as counter in statistics outputs and plots. Default is true.

`# --printBestStat=1 # Print Best/avg/stdev every gen.`
Boolean parameter: toggles screen output of indicated statistics. Default is true.

`# --printPop=0 # Print sorted pop. every gen.`
Boolean parameter: adds a dump of the whole population to the screen every generation. Is likely to generate huge output! Default is false.

`# --printFDC=1 # Print FDC coeff. every gen.`
Boolean parameter: adds Fitness Distance Correlation to output every generation. Default is false.

Section `###### Output - Disk ######`
This second section on Output contains parameters related to DISK output.

`# --resDir=Res # Directory to store DISK outputs`
String parameter: All DISK output will be stored in a separate directory -this is its name. If the directory does not exist, it is created. Note that all graphical displays will use that directory for their temporary files. Also all job dump (see section Persistence below) store their files there too.

`# --eraseDir=0 # erase files in dirName if any`
Boolean parameter: in order not to mix up files from different runs, it is mandatory to ensure that the directory where all files will be stored is empty. However, if this parameter is not set and the directory already exists, an exception is thrown and the program stops. It it is set, all files in the result directory are erased.

`# --fileBestStat=0 # Output Best/avg/stdev to a file`
Boolean parameter: if present, the best, average and standard deviation statistics are stored in file `resDir/best.xg`. Each line contains the generation number, eventualy the evaluation count (depending on parameter `useEval` then the statistics. Default is false.

Section `###### Output - Graphical ######`
This last section on Output contains parameters related to graphical output (only available in Unix through gnuplot at the moment).

`# --plotBestStat=0 # Plot Best/avg Stat`
Boolean parameter: toggles gnuplot output of best and average plots (Linux only at the moment). Default is false.

`# --plotFDCStat=0 # Plot FDC scatter plot`
Boolean parameter: toggles the Fitness Distance Correlation plot (Fitness vs distance to best). Default is false.

`# --plotHisto=0 # Plot histogram of fitnesses`
Boolean parameter: if on, gnuplot is used to plot the sorted population (fitness vs rank). Gives a graphical idea of the diversity. Default is false.

Section `###### Persistence ######`
This section contains parameters handling job dump and restart mechanism.

`# --Load= # -L : A save file to restart from`
String parameter: if present, the initial population (and the RNG) is read from indicated file. That file must come from a previous save (or must be in same format!), i.e. must contain a popualtion, the RNG and all parameters. If no other parameter is modified, using a previously saved population and RNG will give exactly the same results than having run that previous run longer. And a way to be sure to re-use the same parameters is to ... use that very save file as parameter file, as it contains all actual parameters in the right format.
Note that if not enough individuals are read, the remaining are randomly initialized. No default value.

`# --recomputeFitness=0 # -r : Recompute the fitness after re-loading the pop.?`
Boolean parameter: in case some individuals are read from a file, their fitness is read too. If this one is true, it is nevertheless recomputed. Default is false i.e. use fitnes that's in the file.

`# --saveFrequency=0 # Save every F generation (0 = only final state, absent = never)`
Integer parameter: interval between two dump to disk of the whole population (+RNG + parameters), in a file named genNN.sav in the `dirRes` directory, where NN is the generation number. If this prameter is present (even with 0 or negative value), the final population will always be saved, whatever the reason for stopping. Hence the only way to avoid all saves is to omit the parameter (there is no default value).

`# --saveTimeInterval=0 # Save every T seconds (0 or absent = never)`
Integer parameter: time interval between two population (+RNG + parameters) dumps to disks. Files are names timeNN.sav. See pervious parameter description for ore details. No default value.

`# --status=t-eoGA.status # Status file`
String parameter: name of the status file (that contains all parameters in the input format). There is no way to avoid creating that file except recompiling ... or giving the name /dev/null (Unix). Default value is ProgramName.status

Section `###### Stopping criterion ######`
This section allows to decide when the algorithm will stop.

`# --maxGen=100 # -G : Maximum number of generations (0 = none)`
Integer parameter: maximum number of generations. A value of 0 disables that stopping criterion. Default is 100.

`# --steadyGen=100 # -s : Number of generations with no improvement`
Integer parameter: stops whenever that number of generations is passed without any improvement of the best fitness in the population, provided the following minimum number of generations has been done. No default value.

`# --minGen=0 # -g : Minimum number of generations`
Integer parameter: the above steadyGen parameter starts its job only after that minimum nuber of generations is passed. No default value.

`# --maxEval=0 # -E : Maximum number of evaluations (0 = none)`
Integer parameter: maximum number of generations. No default value.

`# --targetFitness=0 # -T : Stop when fitness reaches`
Real-valued parameter: the algorithm stops whenever the best fitness reaches that target. No default value.

`# --CtrlC=0 # -C : Terminate current generation upon Ctrl C`
Boolean parameter: if true, Ctrl C only stops after the current generation as completed (eventually dumping population to a file if some saver is active). This very useful feature is only available in Unix at the moment. Default is false.

User's guide:Bistring specific parameters
The following describes the specific parameters that are available in program BitEA to evolve genotypes that are bitstrings.
The two representation-dependent sections are concerned repectively with genotype initilization and variation operators.

Section `###### Genotype Initialization ######`
This section should allow input if all necessary parameters for genitype initialization

`# --ChromSize=10 # -n : The length of the bitstrings`
Integer parameter: The bitstring initilization only requires the length of the chromosome.

Section `###### Variation Operators ######`
This section allows to tune the way the variation operators will be applied to the individuals (in the strict limit of SGA model at the moment, see below).

`# --operator=SGA # -o : Description of the operator (SGA only now)`
String parameter: Describes the way the operators are applied. At the moment, only SGA is available. SGA sequentially applies a (quadratic) crossover operator with probability `pCross` and a mutation operator with probability `pMut`. Both these operators can in turn be proportional combinations of simple operators of the same arity.

`# --pCross=0.6 # -C : Probability of Crossover`
Floating-point parameter: The probability that a given couple of selected genitors is applied the crossover operator. In SGA operator model, each couple of selected genitors is applied the crossover operator with that probability (and remains unchanged with probability `1-pCross`. Whenever a couple undergoes crossover, a choice is made upon available crossover operators proportionaly to their relative rates (see below). Default is 0.6.

`# --pMut=0.1 # -M : Probability of Mutation`
Floating-point parameter: The probability that a given individual (resulting from a crossover or a non-crossover operation, see above) is applied the mutation operator. Whenever an individual undergoes mutation, a choice is made upon available mutation operators proportionaly to their relative rates (see below). Default is 0.1.

`# --onePointRate=1 # -1 : Relative rate for one point crossover`
Floating-point parameter: Rate of aplication of the 1-point crossover relatively to 2-point and uniform below (see `pCross` parameter). Default is 1.

`# --twoPointRate=1 # -2 : Relative rate for two point crossover`
Floating-point parameter: Rate of aplication of the 2-point crossover relatively to 1-point above and uniform below (see `pCross` parameter). Default is 1.

`# --uRate=2 # -U : Relative rate for uniform crossover`
Floating-point parameter: Rate of aplication of the 1-point crossover relatively to 1- and 2-point above (see `pCross` parameter). Default is 2.

`# --pMutPerBit=0.01 # -b : Probability of flipping 1 bit in bit-flip mutation`
Floating-point parameter: When `bit-flip mutation` is applied, each bit is flipped independently with probability `pMutPerBit`.

`# --bitFlipRate=0.01 # -s : Relative rate for bit-flip mutation`
Floating-point parameter: Rate of aplication of the bit-flip mutation relatively to one-Bit mutation below (see `pMut` above). Default is 0.01 (if all relative rates are equal, the choice is uniform among available operators).

`# --oneBitRate=0.01 # -d : Relative rate for deterministic bit-flip mutation`
Floating-point parameter: Rate of aplication of the one-bit mutation relatively to bit-flip mutation below (see `pMut` above). One-bit mutation flips one and only one bit, uniformly chosen in the individual. Default is 0.01 (if all relative rates are equal, the choice is uniform among available operators).

User's guide:Real-valued specific parameters
To run your own real-valued application, write your fitness function (see `real_value.h`), recompile, and run from the command line

`RealEA @RealEA.param`
in order to use sensible parameters! (see Lesson 3 for details on the parameter file). But remember that Self-adaptive ES will work much better!
The following describes the specific parameters that are available in programs `RealEA` and `ESEA` to evolve genotypes that are vector<double>.
`RealEA` implements what can be called a "real-coded GA", where everything is identical to the bitstring case above (except initialization and operators that are specific to vector<double> of course) and `ESEA` implements the full Evolution-Strategy self-adaptive mutation mechanism - together with specific ES crossover operators. The initialization section for both programs are identical, but the operator sections are totally different. See next paragraph for a description of ES specific parameters.

Section `###### Genotype Initialization ######`
This section should allow input if all necessary parameters for genitype initialization

`# --vecSize=10 # -n : The number of variables`
Integer parameter: The initilization requires the length of the vector<double>.

`# --initBounds=10[-1,1] # -B : Bounds for uniform initialization`
Bounds parameter: Bounds for uniform initialization of the real variables. The syntax for this parameter given in the `objectBounds` parameter description below. This argument is mandatory, furthermore the given bounds must be bounded. The default is [-1,1] for all variables.
Note that this parameter is independent of the `objectBounds` parameter below.

`# --sigmaInit=0.3 # -s : Initial value for Sigma(s)`
Floating-point parameter: The initial value for all standard-deviation mutation strategy parameters. Useless when no self-adaptive mutation mechanism is used.

Section `###### Variation Operators ######`
This section allows to tune the way the variation operators will be applied to the individuals (in the strict limit of SGA model at the moment, see below).

`# --objectBounds=10[-inf,+inf] # -B : Bounds for variables`
Bounds parameter: Bounds for object variables. The syntax for this parameter is a succession of (optionally semi-colon separated) items of the form `N[min,Max]`where the optional integer `N` indicates how many variables have the given bounds. `min` and `Max` are either floating point numbers, or `-inf` (resp. `+inf`) to indicate unbounded direction. If not enough bounds are provided, the remaining variables will have the same bounds as the last bounds given.
This argument is mandatory, and default is [-inf,+inf], i.e. unbounded variables.

Examples: `10[-1,1]`is equivalent to simply `[-1,1]` or to the extended `[-1,1][-1,1][-1,1][-1,1][-1,1][-1,1][-1,1][-1,1][-1,1][-1,1]`.
And `[-1,1];2[0,1];[-inf,10]`results in the first variable staying in [-1,1], the second and the third in [0,1] and all remaining variables below 10.

`# --operator=SGA # -o : Description of the operator (SGA only now)`
String parameter: Describes the way the operators are applied. At the moment, only SGA is available. SGA sequentially applies a (quadratic) crossover operator with probability `pCross` and a mutation operator with probability `pMut`. Both these operators can in turn be proportional combinations of simple operators of the same arity.

`# --pCross=0.6 # -C : Probability of Crossover`
Floating-point parameter: The probability that a given couple of selected genitors is applied the crossover operator. In SGA operator model, each couple of selected genitors is applied the crossover operator with that probability (and remains unchanged with probability `1-pCross`. Whenever a couple undergoes crossover, a choice is made upon available crossover operators proportionaly to their relative rates (see below). Default is 0.6.

`# --pMut=0.1 # -M : Probability of Mutation`
Floating-point parameter: The probability that a given individual (resulting from a crossover or a non-crossover operation, see above) is applied the mutation operator. Whenever an individual undergoes mutation, a choice is made upon available mutation operators proportionaly to their relative rates (see below). Default is 0.1.

`# --alpha=0 # -a : bound for combination factor in real crossover`
Floating-point parameter: Bound for the choices of linear combination factors in both crossover belows (similar to BLX-alpha notation). Default is 0 (i.e. combination factor are chosen in [0,1]).

`# --segmentRate=1 # -s : Relative rate for segment crossover`
Floating-point parameter: Rate of application of the segment crossover relatively to hypercube and uniform crossovers (see `pCross` parameter). Segment crossover generates offspring uniformly on the segment joining both parents, i.e. constructs two linear combinations of the parents with a random number uniformly drawn in [`alpha`,1+`alpha`]. Default is 1.

`# --hypercubeRate=1 # -A : Relative rate for hypercube crossover`
Floating-point parameter: Rate of application of the hypercube crossover relatively to segment and uniform crossovers (see `pCross` parameter). Hypercube crossover generates offspring uniformly on the hypercube whose diagonal is the segment joining both parents, i.e. by doing linear combinations of each variable independently (a random number in [`alpha`,1+`alpha`] is drawn anew for each variable). Default is 1.

`# --uxoverRate=1 # -A : Relative rate for uniform crossover`
Floating-point parameter: Rate of application of the segment crossover relatively to hypercube and segment crossovers (see `pCross` parameter). Uniform crossover simply exchanges values of variables, i.e. uniformly picks up two other summits of the hypercube defined by the parents. Default is 1.

`# --epsilon=0.01 # -e : Half-size of interval for Uniform Mutation`
Floating-point parameter: The uniform and deterministic-uniform mutations will choose values of variable X uniformly in `[X-epsilon, X+epsilon]`. Default is 0.01.

`# --uniformMutRate=1 # -u : Relative rate for uniform mutation`
Floating-point parameter: Rate of aplication of the uniform mutation relatively to determinitic uniform and the normal mutations (see `pMut` above). Uniform mutation modifies all variables by choosing new values uniformly on an interval centered on the old value of width `2*epsilon` (see above). Default is1.

`# --detMutRate=1 # -d : Relative rate for deterministic uniform mutation`
Floating-point parameter: Rate of aplication of the determinisitc-uniform mutation relatively to uniform and normal mutations (see `pMut` above). Deterministic-uniform mutation modifies one single variable uniformly based on epsilon `epsilon`. Default is1.

`# --normalMutRate=1 # -d : Relative rate for Gaussian mutation`
Floating-point parameter: Rate of aplication of the normal mutation relatively to two uniform mutations above (see `pMut` above). Default is1.

`# --sigma=0.3 # -s : Sigma (fixed) for Gaussian mutation`
Floating-point parameter: The value of standard deviation for Gaussian mutation - fixed along evolution (see the Evolution Strategy program below for self-adaptive mutations).

User's guide:ES with self-adative mutation parameters
To run your own SA-ES application, write your fitness function (see `real_value.h`), recompile, and run from the command line

`ESEA @ESEA.param`
in order to use sensible parameters! (see Lesson 3 for details on the parameter file).
The following describes the specific parameters for program `ESEA`, that implements the full Evolution-Strategy self-adaptive mutation mechanism - together with specific ES crossover operators. The initialization section is the same as the one for plain vector<double> above, so only the opeartor sections will be described here. A new section is now concerned with deciding what kind of self-adaptive mutation strategy will be applied - it has been separated from the other variation operators because it has consequences on the choice of the genotype.
Warning: if you choose not to use any self-adaptive mechanism (i.e. setting all parameters of this section to false) you end up with ... an algorithm that is identical to `RealEA` above (try it and take alook at the status file).

Section `###### ES mutation ######`
This section allows to decide which type of self-adaptive mutation will be used. There are three available types: isotropic mutation, using one standard deviation for each individual, that will be applied to all variables; anisotropic mutation, where each individual carries as many standard deviations as it has variables; and correlated mutation where each individuals has its own full correlation matrix.

`# --Isotropic=1 # -i : Isotropic self-adaptive mutation`
Boolean parameter: If true, at least one self-adaptive parameter will be used for each individual. Default is true.

`# --Stdev=0 # -s : One self-adaptive stDev per variable`
Boolean parameter: If true, at least one self-adaptive parameter per variable will be used for each individual. Default is false.

`# --Correl=0 # -c : Use correlated mutations`
Boolean parameter: If true, full correalted self-adaptive mutation will be used for each individual. Default is false.

Note: The default values result in an isotropic self-adaptive mutation to be chosen.

Section `###### Variation Operators ######`
Only the parameters that are specific to ESEA are presented here - the `objectBounds,operator,pCross` and `pMut` are exactly the same as for `RealEA` above.

`# --crossType=global # -C : Type of ES recombination (global or standard)`
String parameter: Es crossover can involve only two parents - and it is then identical to the `standard` hypercube crossover describe for the `RealEA` parameters above. But new parents can also be chosen anew for each variable before doing the crossover for that variable - and this is called `global` recombination.

`# --crossObj=discrete # -O : Recombination of object variables (discrete or intermediate)`
String parameter: There are two possible crossovers in plain ES. The `discrete` crossover simpy exchanges variables among the parents. It is similar to the plain uniform crossover for real variables. The crossover performs a linear combination of parents;variables - it si similar to the hypercube crossover described for with alpah parameter set to 0. This parameter allso to choose the type of crossover that will be applied to the object variables (i.e. the origianl variables of the problem). Default is discrete.

`# --crossStdev=intermediate # -S : Recombination of mutation strategy parameters (intermediate or discrete)`
String parameter: This parameter allows to choose the type of crossover (see above) that will be applied to the mutation strategy parameters that are part of the genotype. Default is intermediate.

`# --TauLoc=1 # -l : Local Tau (before normalization)`
Floating-point parameter: The local factor for the mutation of the mutation strategy parameters (the only one used when a single standard deviation is used). Default is 1.

`# --TauGlob=1 # -g : Global Tau (before normalization)`
Floating-point parameter: The global factor for the mutation of the mutation strategy parameters (only useful when more than one standard deviation are used). Default is 1.

`# --Beta=0.0873 # -b : Beta`
Floating-point parameter: The factor for the mutation of the rotation angles in the case of the full correlated mutation. Default is 0.0873 (following Schwefel).

Programmer's guide

At the moment, you will have to browse in the source (colored!) code (Bit - Real) almost by yourself, sorry.

Note that the main file is now very slim, as it only contains calls to some `make_xxx` functions - these functions contain the actual code, very similar to the code of Lesson3, except for the memory management, performed through an `eoState` object (notice that all `make_xxx` calls have an eoState as second parameter).

Programmer's guide: The make_xxx files

Interface: all `make_xxx` files have as first two parameters an `eoParser` and an `eoState`. The `eoParser` is be used within all functions to parse the command-line and/or a parameter file in order to read any relevant user-parameter, while the `eoState` is used here to store all pointers to be allocated inside the function (see Programming hints for more detailed explanations).

There are 2 types of `make_xxx` files: the ones that do depend on representation, defining the genotype and initialization (`make_genotype_xxx`, with xxx being the type of genotype) and variation operators (`make_op_xxx`), and the one that are truly representation-independent (`make_pop, make_continue, make _checkpoint, make_algo` and `make_run`).
The former are located in the directory corresponding to the actual genotype (`src/ga` for eoBit, `src/es` for eoReal and all eoESxxx genotypes). The latter are in the directory `src/do.`

If you take a close look at the code of `make_continue` for instance, you will first notice that ... the function declared there is called `do_make_continue` and is not the one you are calling in the main file, though it has the same parameters as arguments.
The explanation lies within the file `make_continue_xxx.cpp` (with xxx = ga or real/es)which, as its color (and name) should have told you about, are representation-dependent: in fact the `make_continue_xxx.cpp` files only instanciates the general <EOT> template into one of the possible template for eoBit or eoReal/eoES - and this trick allows to compile them separately!

The other thing that you should notice is that the code there is very similar to the code that was in Lesson 3, regarding parameter reading and type of object that are allocated - except for memory management. This goes for all `make_xxx` files - so the only thing you need to understand how it goes is to look at the memory management section.

Pros: you don't have to handle a huge main function - and many of the make_xxx files can be directly used in different applications (this is called modularity :-)))
More interesting, you can even compile the `make_xxx` files separately for a given target template, and link them e.g. with your fitness function when it is ready (remember that up to now you needed to compile everything altogether by including the code into your mail fine). Indeed, if you do a global make, you will notice that there are additional libraries compiled in `src/ga` and `src/es` ...

Cons: It makes the code a little more complex to understand, first because of the indirection needed for pre-compilation with a given template, and second because of the memory management that this imposes.

Programmer's guide: Memory management
As already said, all functions have an `eoState` as second argument - and that object is used to store the functor objects that were simply declared as variables of the main function up to now : see Programming hints for more detailed explanations and take a look at the code of `make_continue` for instance, you will see the implementation of the memory management in action.

Programmer's guide: Memory management of eoParam objects

It has been seen in Lesson 3 that parameters could be read from command-line and/or a parameter file using an `eoParser` object. However, the memory mangement problem also concerns EO parameter objects (`eoParam`): the way there are read in Lesson3 makes them local variables of the function they are defined in.
It is however possible to ask the `eoParser` to hold them, as done for instance in eoContinue for the maximum number of generations. Local declaration would amount to something like :

`eoValueParam<unsigned int>& maxGenParam(100, "maxGen", "Maximum number of generations () = none)",'G');`
`parser.processParam( maxGenParam, "Stopping criterion" );`
`unsigned maxGen = maxGenParam.value();`

while if you want the parser to hold those eoParam objects, you will write something like

`eoValueParam<unsigned>& maxGenParam = _parser.createParam(unsigned(100), "maxGen", "Maximum number of generations () = none)",'G',"Stopping criterion");`

and then use `maxGenParam.value()` to get the value enterred by the user. In that case, you get a reference to an eoParam object that is hold by the eoParser - and deleted whith it.
Note that there are two important differences between the arguments of the constructor of an eoParam object and the method createParam of an eoParser object: first, you need to provide the additional section parameter (used only when outputting the eoParser); second you must make sure that the first argument is of the correct type otherwise the compiler will complain.

Note that if you don't later need the eoParam, but simply its value, you can even diretly write

`unsigned maxGen = _parser.createParam(unsigned(100), "maxGen", "Maximum number of generations () = none)",'G',"Stopping criterion").value();`

Getting parameter values in different functions:

It is often useful (though probably very bad programming style :-))) to be able to get the value of a user-defined parameter in two different places of the code without passing it around through many levels of call. You can then use the alternate function `getORcreateParam` with exactly the same syntax than `createParam`.
Be careful that the link between both parameters is made through their longmanes (second argument), and that you must so hard-code that name in two different places with of course exactly the same spelling!!!
Examples can be found for instance in the make_genotype_xxx files, for the sizes of the genotypes: it is often the case that the definition of the optimization problem requires (or computes) such size. The idea is then that you either read or compute that size, then create a (dummy) parameter with the name that is used later in the make_genotype file. For instance, for bitstrings, the make_genotype_ga.h contains the following line defining the size of the bitstring

`unsigned theSize = _parser.getORcreateParam(unsigned(10), "chromSize", "The length of the bitstrings", 'n',"Problem").value();`

If you want to define that size earlier, you should write somewhere before

`unsigned requiredSize = ... ;`
`_parser.createParam(requiredSize, "chromSize", "The length of the bitstrings", 'n',"Problem");`

Of course, if that size is mandatory, you should NOT modify it at run-time by entering anther value !

User's guide: General - Bitstring - Real - ES - Programmer's guide: General - Memory management - Parameters

Lesson 3 - Lesson 5 - Main page - Algorithm-Based - Component-Based - Hints - EO documentation

Last modified: None of your business!