From 1f1f59831472412d092400be8998c5c4775e8e0d Mon Sep 17 00:00:00 2001 From: AI Xin Date: Sun, 8 May 2022 18:59:34 +0800 Subject: [PATCH] add mo tutorial doc in Markdown format The original tutorial link[http://paradiseo.gforge.inria.fr/index.php?n=Doc.Tutorials] is broken. I found the archive from here: https://web.archive.org/web/20210119160107/http://paradiseo.gforge.inria.fr/index.php?n=Doc.Tutorials --- mo/tutorial/Lesson1/README.md | 448 ++++++++++++++++++ mo/tutorial/Lesson1/schemaLS.jpg | Bin 0 -> 30185 bytes mo/tutorial/Lesson2/README.md | 124 +++++ mo/tutorial/Lesson3/README.md | 110 +++++ mo/tutorial/Lesson4/README.md | 67 +++ mo/tutorial/Lesson5/README.md | 64 +++ mo/tutorial/Lesson6/README.md | 250 ++++++++++ .../Lesson6/multimodalFitnessLandscape.jpg | Bin 0 -> 19455 bytes mo/tutorial/Lesson7/README.md | 60 +++ 9 files changed, 1123 insertions(+) create mode 100644 mo/tutorial/Lesson1/README.md create mode 100755 mo/tutorial/Lesson1/schemaLS.jpg create mode 100644 mo/tutorial/Lesson2/README.md create mode 100644 mo/tutorial/Lesson3/README.md create mode 100644 mo/tutorial/Lesson4/README.md create mode 100644 mo/tutorial/Lesson5/README.md create mode 100644 mo/tutorial/Lesson6/README.md create mode 100755 mo/tutorial/Lesson6/multimodalFitnessLandscape.jpg create mode 100644 mo/tutorial/Lesson7/README.md diff --git a/mo/tutorial/Lesson1/README.md b/mo/tutorial/Lesson1/README.md new file mode 100644 index 000000000..466986cd3 --- /dev/null +++ b/mo/tutorial/Lesson1/README.md @@ -0,0 +1,448 @@ +# How to implement your first hill-climber algorithm? +This lesson will let you +* Run your first simple Hill-Climber within MO library +* Learn the main principles of MO +* Browse through the code of these algorithm +* Run other kind of Hill-Climbers: first-improvment, random best, neutral hill-climbers. +* Design your own evaluation functions +* Add your own stopping criteria + +## 1. I want to run my first hill-climber! +If you followed the the Install instructions, all examples would be compiled. If it is not the case, refer to the above instructions. + +You can run your hill-climber. From the "build/mo/tutorial/Lesson1" directory, type: +```shell +./lesson1_simpleHC -V=20 +``` +Great! A very simple hill-climber had solved the oneMax problem (which maximizes the number of ones in the bit string) for the bit strings of size 20. On your output screen, you can see on the first line the random initial solution, and the second line, the final solution which is (I hope) the bit string of size 20 with all ones. For example: +```text +initial: 6 20 00010000011000100101 +final: 20 20 11111111111111111111 +``` +The first number is the fitness of the solution, the second the size of the bit string and following all the bits of the solution. + +## 2. The main principles of MO +In MO a local search is defined by this schema: + +![](./schemaLS.jpg) + +At each iteration, from the current solution: +* Generate neighbors from the neighborhood and evaluate them +* Select a neighbor +* Decide to replace solution by the selected neighbor + +Like in paradisEO-eo, MO separates the representation-dependent part (represention of solution, neighbor, evaluation) from the generic part (the order of neighbors generation, selection, replacement, etc.). + +So, to define a local search, it is necessary to define: +* the solution representation, +* the neighbor representation, +* the evaluation function of a solution, +* the evaluation function of a neighbor, +* the neighborhood (generation of the neighbors) + +If you can define the representation-dependent part of your problem, you can use all local search algorithms from MO (Hill-climbing, simulated annealing, tabu search, iterated local search, variable neighborhood search, and more) and even combined them with evolutionary algorithms ! + +Of course a lot of classical representations, neighborhoods and problems are already defined in MO. They will be explained all along this tutorial. +Let's first have a look on the oneMax problem solved by a simple Hill-Climber algorithm defined as follows: +```text +Choose randomly initial solution x +Do + best <- first neighbor of x + For all y in the neighborhood of x + If (f(y) > f(best)) + best <- y + endif + endfor + If (f(x) < f(best)) + x <- best + continue <- true + else + continue <- false + endif + While continue == true +``` + +The simple HC stops on local optima when no improvement can not be made. + +## 3. Browsing the code + +Now let's have a look on the code. All the elements of the simple HC are already defined in the MO framework, and the code only puts all this bricks together. The code following the previous general principles. It defines the solution and neighbor representation, the solution and neighbor evaluation, the neighborhood, and the local search used. +Please, open the file "mo/tutorial/Lesson1/lesson1_simpleHC.cpp", and follow me in the code: + +### 1. The includes part: + +The general includes for the c++ stdlib streams: +```c++ +#include +#include +#include +#include +#include +``` + +This includes for eo which contains all include files of EO: +```c++ +#include +``` + +The first line to include the bit string representation defined in eo, and the second one to include the bit string neighbor representation. All classical problem-dependent part of MO are defined in the sub-directory "problems". How to define your representation is explained in EO tutorial, and how to design your neighbor will be explain in the next lesson 2. Here just use it. +```c++ +#include +#include +``` + +This includes the evaluation function of a solution (full evaluation), the incremental evaluation of a neighbor for the oneMax problem, and a possible evaluation of neighbor using the full evaluation. You will learn at the end how to define your evaluations. +```c++ +#include +#include +#include +``` + +This neighborhood visits all bit string at Hamming distance 1 in increasing order of bit index from bit 0 to bit vecSize-1. All the neighborhoods are included in the "neighborhood" directory. +```c++ +#include +``` + +Now we can include the simple hill-climbing local search. All local search algorithms are included in the "algo" directory. +```c++ +#include +``` + +### 2. The typedef part: + +EO can apply an evolutionary algorithm on any type of solution. So, all EO classes are parametrized by the type of solutions, and it is useful to use a synonym (with a typedef) of the solution's type. +MO can apply an local search algorithm on any type of solution and neighbor. So, for the same reason, all classes of MO are parametrized by the neighbor's type. In the neighbor class, the solution's type is defined. More precision on the neighbor design will be given in the lesson 2. +Here the solution representation is a bit string and the neighbor representation is related to a bit string solution and Hamming distance 1 (only 1 bit can be flipped), both using an "unsigned int" fitness value. +```c++ +typedef eoBit Indi; +typedef moBitNeighbor Neighbor; +``` + +### 3. Object definition part: + +Follows the main function "main_function" where all useful objects are defined.\\ +First, a code to parse the command line and a file. It gives the value of the random seed and the size of bit string. The lesson 3 of EO tutorial gives more precision on this code. Here we have only to understand that the variables "seed" and "vecSize" are initialized. +```c++ +eoParser parser(argc, argv); + +eoValueParam seedParam(time(0), "seed", "Random number seed", 'S'); +parser.processParam( seedParam ); +unsigned seed = seedParam.value(); + +// length of the bit string +eoValueParam vecSizeParam(8, "vecSize", "Genotype size", 'V'); +parser.processParam( vecSizeParam, "Representation" ); +unsigned vecSize = vecSizeParam.value(); +(...) +``` + +To seed the random seed (see lesson 1 of EO tutorial for more precision): +```c++ +rng.reseed(seed); +``` + +The definition the initialization of solutions is not defined is MO but in EO. The "eoInitFixedLength" is a class that makes a random intialization of bit string of a given length. Each bit is true with 1/2 rate. You can see the lesson 1 of EO tutorial lesson 1 for more precision. +```c++ +eoUniformGenerator uGen; +eoInitFixedLength random(vecSize, uGen); +``` + +The fitness function of the oneMax problem is the number of 1 in the bit string. It is already defined in MO: +```c++ +oneMaxFullEval fullEval; +``` + +A neighbor is not necessary a modified copy of the solution. But often a neighbor defines how to move, i.e. how to modify a solution to compute the neighbor. For example, for the bit string, a neighbor indicates which bit is flipped. +In the same way, it is often possible to define the incremental evaluation of a neighbor knowing the modification (the move). +The incremental evaluation for the oneMax problem is already defined and adds +1 or -1 at the fitness value according to the flipped bit. +```c++ +moOneMaxIncrEval neighborEval; +``` + +When the incremental evaluation can not be defined. The neighbor can be evaluated with the full evaluation. First the solution is modified on the neighbor, than the full evaluation is computed on it and then the solution is move back. This is done by the class "moFullEvalByModif". If you want you to test it comment the line with moOneMaxIncrEval and uncomment the line with moFullEvalByCopy: +```c++ +// moFullEvalByModif neighborEval(fullEval); +``` + +For the simple hill-climbing, all the neighbors are explored in increasing order of their bit flip. So, you can use the class "moOrderNeighborhood" where the size of the neighborhood has to be precise in the constructor: +```c++ +moOrderNeighborhood neighborhood(vecSize); +``` + +All representation-dependent part is now defined, so the simple Hill-Climbing can be defined. The constructor needs the neighborhood, the solution and neighbor evaluations. The solution and neighbor representation are defined by the template of the class: +```c++ +moSimpleHC hc(neighborhood, fullEval, neighborEval); + +``` + +### 4. The execution of hill-climbing part: + +Always in the "main_function" function, it is the execution part. +In MO, the local search algorithm never initializes the solution. It must be made outside the local search algorithm. This allows to combine local search algorithms with evolutionary algorithms or with others local search algorithms. +Now apply your local search on the solution as follows: +```c++ +// The current solution +Indi solution; + +// random initialization +random(solution); + +// Evaluation of the intial solution: +// can be evaluated here, or else it will be done at the beginning of the local search +fullEval(solution); + +// output: the initial solution +std::cout << "initial: " << solution << std::endl ; + +// apply the local search on the solution ! +hc(solution); + +// output: the final solution +std::cout << "final: " << solution << std::endl ; +``` + +The main line is "hc(solution)" which apply the local search on the solution. +Easy, isn't it? + +## 4. Others hill-climbing algorithms + +You may think that the simple hill-climbing is not the hill-climbing you need because you don't want to explore all the neighborhood or because there is several solutions with the same fitness value. + +You may want to implement the first improvement hill-climbing defined as follows: +```text +Choose randomly initial solution x +Do + y <- not visited random neighbor of x + If (f(x) < f(y)) + x <- y + else + y.visited <- true + endif + While number of non visited neighbor of x > 0 +``` + +In the first improvement HC, if the fitness of a random neighbor is higher than the current fitness, the neighbor is selected. And this hill-climber stops on local optima when no more fitness improvement can be made in the neighborhood. + +To implement the first improvement HC, you have to change only 2 lines in the previous code. +The one to change the neighborhood generation: +```c++ +moRndWithoutReplNeighborhood neighborhood(vecSize); +``` +In this neighborhood, the neighbors are generated in an randomly order (not from 0 to vecSize-1) without replacement which means that the neighbors are generated only once. + +And of course, the other one to change the local search algorithm: +```c++ +moFirstImprHC hc(neighborhood, fullEval, neighborEval); +``` + +The corresponding include files have to be changed too. See and run the code "mo/tutorial/Lesson1/lesson1_firstImprHC.cpp". + +For a hill-climbing which takes care on the solutions with equal fitness value such as this one: +```text +Choose randomly initial solution x +Do + bestVect <- [ first neighbor of x ] + For all y in the neighborhood of x + If (f(y) > f(bestVect.first)) + bestVect <- [ y ] + else if (f(y) == f(bestVect.first) and y != bestVect.first) + bestVect.push_back(y) + endif + endfor + If (f(x) < f(bestVect.first)) + x <- choose randomly a solution from bestVect + continue <- true + else + continue <- false + endif + While continue == true +``` + +You only have to change the local search algorithm by (see the code in mo/tutorial/Lesson1/lesson1_randomBestHC.cpp) : +```c++ +moRandomBestHC hc(neighborhood, fullEval, neighborEval); +``` + +Easy, isn't it? + +And if you don't want that your hill-climber stops if there is some solution with the same fitness in the neighborhood like this: +```text +nbStep <- 0 +Choose randomly initial solution x +Do + bestVect <- [ first neighbor of x ] + For all y in the neighborhood of x + If (f(y) > f(bestVect.first)) + bestVect <- [ y ] + else if (f(y) == f(bestVect.first)) + bestVect.push_back(y) + endif + endfor + If (f(x) <= f(bestVect.first)) + x <- choose randomly a solution from bestVect + continue <- true + else + continue <- false + endif + nbStep <- nbStep + 1 + While continue == true and nbStep > nbStepMax +``` + +This hill-climber stops on strict local optima, but not plateau which are local optima. So, another parameter is need to stop the algorithm (nbStepMax). Then you only have to change the local search algorithm by (see the code in Lesson1/lesson1_neutralHC.cpp) : +```c++ +moNeutralHC hc(neighborhood, fullEval, neighborEval, nbStepMax); +``` + +Easy, isn't it? + +## 5. Define your evaluation + +### 1. Evaluation of solutions: +You can learn to define your fitness function in the EO tutorial lesson 1. But let's me shortly explain how to do. +You have to define a class inherited from the "eoEvalFunc". For example, the oneMaxFullEval is defined as follows: +```c++ +#include +template< class EOT > +class oneMaxFullEval : public eoEvalFunc +{ +public: + + /** + * Count the number of 1 in a bitString + * @param _sol the solution to evaluate + */ + void operator() (EOT& _solution) { + unsigned int sum = 0; + for (unsigned int i = 0; i < _solution.size(); i++) + sum += _solution[i]; + _solution.fitness(sum); + } +}; +``` + +The file "eoEvalFunc.h" must be included at the begining. The class "oneMaxFullEval" inherits from the "eoEvalFunc" class. Like all class in EO, the classes are templatized by the solution type "EOT". +EO uses a functor style: the fitness function is computed in the method "operator()(EOT& _sol)". Do what you want to compute the fitness value in this method, and puts the fitness value in the solution at the end by using its method "fitness": +```c++ +_solution.fitness( fitnessValue ); +``` + +The "eoBit" class is vector of boolean. The size of the vector is obtained by the method "size()": +```c++ +_solution.size() +``` +and the value of the ith bit is given by the classical method "operator[]": +```c++ +_solution[i] +``` +The fitness value of a solution can be obtained with the method "fitness()": +```c++ +_solution.fitness() +``` + +### 2. Evaluation of neighbors: +MO uses the same idea to evaluate a neighbor. You have to define a class which inherits from "moEval" class. For example, the oneMaxIncrEval is defined as follows: +```c++ +#include +template< class Neighbor > +class moOneMaxIncrEval : public moEval +{ +public: + + typedef typename Neighbor::EOT EOT; + + /* + * incremental evaluation of the neighbor for the oneMax problem + * @param _solution the solution to move (bit string) + * @param _neighbor the neighbor to consider (of type moBitNeigbor) + */ + virtual void operator()(EOT & _solution, Neighbor & _neighbor) { + if (_solution[_neighbor.index()] == 0) + _neighbor.fitness(_solution.fitness() + 1); + else + _neighbor.fitness(_solution.fitness() - 1); + } +}; + +``` + +The file "moEval.h" must be included at the begining. All class to define evalutation function are in the "eval" directory of MO. The class "oneMaxIncrEval" inherits from the "moEval" class. Like all class in MO, the classes are templatized by the neighbor's type "Neighbor". +A typedef is defined to easily have access to the solution type "EOT". The solution type is the type "EOT" in the class of Neighbor: +```c++ +typedef typename Neighbor::EOT EOT; +``` + +MO also uses a functor style: the evaluation function is computed in the method "operator()(EOT& _solution, Neighbor & _neighbor)" which depends on the current solution and its neighbor to consider. Do what you want to compute the fitness value of the neighbor in this method, and puts the fitness value in the neighbor by using its method "fitness": +```c++ +_neighbor.fitness( fitnessValue ); +``` + +The "moBitNeighbor" has a method "index()" which gives the number of flipped bit. When the flipped bit of the solution is set to "0" the number of 1 in the neighbor is increased by one, and decreased by one otherwise. +When it is possible the incremental evaluation of neighbor gives a better complexity. For example the full evaluation needs vecSize comparisons, and the incremental evaluation only one comparison. +This prototypical example helps you to define your own solution and neighbor evaluations ! + +### 6. Use your stopping criteria + +All local search algorithms have their own stopping criteria, but it is possible to add other stopping criteria. The predefined stopping criteria you can add are: +* stop on the number of iterations +* stop on the number of full evaluation +* stop on the number of neighbor evaluation +* stop on the fitness value reached +* stop on a time limit + +All criteria inherit from the class "moContinuator" in the directory "continuator". To use one of them, you have to include the correct file, to define your object from the class and add the continuator to the local search constructor. +For example, to add a maximum number of iteration to your simple hill-climber. First include the correct file: +```c++ +#include +``` + +Define an object from the class: +```c++ +moIterContinuator continuator(iterMax); +``` + +And add the continuator in the constructor of the HC: +```c++ +moSimpleHC hc(neighborhood, fullEval, neighborEval, continuator); +``` + +Examples on all continuators are given in the source codes "lesson1_iterContinuator.cpp", "lesson1_fitContinuator.cpp", "lesson1_fullevalContinuator.cpp", "lesson1_evalContinuator.cpp". + +It is also possible to combine several continuators with the class "moCombinedContinuator.h" as follows: +```c++ +moIterContinuator iterCont(iterMax); +moFitContinuator fitCont(fitnessMax); +moFullEvalContinuator fullevalCont(fullEval, fullevalMax); +moNeighborEvalContinuator evalCont(neighborEval, evalMax); + +moCombinedContinuator continuator(iterCont); +continuator.add(fitCont); +continuator.add(fullevalCont); +continuator.add(evalCont); +``` + +The local search stops when one of the continuators is false. +Easy, isn't it? + +Of course, you can define your own continuator. You must inherit your own class from the "moContinuator" class. Then 2 methods must be defined: +* the test method: + ```c++ + virtual bool operator()(EOT & _solution) + ``` + + The returned value is true when the local search can continue for the next iteration, and false otherwise. + +* the intialisation method: + ```c++ + virtual void init(EOT & _solution) + ``` + Something you want to initialize before starting the local search (for example a counter). + The predefined continuator can help you to define your own continuator. Have fun now! + +## 7. Exercices + +1. Define the evaluation function and the incremental evaluation of the Royal Road problem. And run a first-improvement hill-climber on it! + + The Royal Road is defined in this paper: + "[The Royal Road for Genetic Algorithms: Fitness Landscapes and GA Performance](http://web.cecs.pdx.edu/~mm/handbook-of-ec-rr.pdf)" Mitchell, Forerest, Holland. + +2. Define the evaluation function and the incremental evaluation of the MAX-SAT problem. And run a first-improvement hill-climber on it! \ No newline at end of file diff --git a/mo/tutorial/Lesson1/schemaLS.jpg b/mo/tutorial/Lesson1/schemaLS.jpg new file mode 100755 index 0000000000000000000000000000000000000000..701b9dc7f855c517e2468ba19164aec92f0a8efb GIT binary patch literal 30185 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 E3-^Z@egFUf literal 0 HcmV?d00001 diff --git a/mo/tutorial/Lesson2/README.md b/mo/tutorial/Lesson2/README.md new file mode 100644 index 000000000..8d5d8aba0 --- /dev/null +++ b/mo/tutorial/Lesson2/README.md @@ -0,0 +1,124 @@ +# How to implement and use neighborhoods +In this lesson, you will learn how to implement a neighbor, neighborhood and the evaluation function. Two ways will be show, one generic and one using an indexed neighborhoods. As an example, it will be illustrated on the Queens problem. + +1. Classical neighborhoods (example with a swap operator) +2. Indexed neighbordhoods (example with a shift operator) +3. Evaluation of neighbors +4. Exercise + +## 1. Classical neighborhoods (example with a swap operator) + +### Implementation +To implement a neighborhood for your problem, you must have a class that inherits from "moNeighborhood" and a class that inherits from "moNeighbor" for the corresponding neighbors. As a consequence, in the neighborhood class, you have to implement the following methods: + +hasNeighbor (test if there is at least one valid neighbor) +init (init the first neighbor) +cont (test if there is again a valid neighbor) +next (compute the next valid neighbor) +And in the neighbor class: + +move (how to apply the move corresponding to the neighbor on a solution) +### Example +In the "paradiseo-mo/src/problems/permutation" directory, classical neighborhood and neighbor for swap operator (moSwapNeighborhood.h and moSwapNeighbor.h) are defined. Some methods are specific to the swap operator and you can see a "move_back" methods that is explained at the end of this tutorial. + +In "mo/tutorial/Lesson2" directory, open the source file "testNeighborhood.cpp". You can see how to use this first neighborhood... + +After inclusion, useful types are defined for more lisibility: + +Define type of representation +```c++ +typedef eoInt Queen; +``` +Define type of a swap neighbor +```c++ +typedef moSwapNeighbor swapNeighbor; +``` +Define type of the swap neighborhood +```c++ +typedef moSwapNeighborhood swapNeighborhood; +``` +And in the "main" fonction, a neighborhood, a solution and a neighbor are declared: +```c++ +swapNeighborhood swapNH; +Queen solution; +swapNeighbor n1; +``` + +Then they are used to explore and print all the neighbors of the neighborhood for a Queen problem of size 8 (swapEval is the evaluation function declared previously) +```c++ +swapNH.init(solution, n1); +swapEval(solution,n1); +n1.print(); +while(swapNH.cont(solution)){ + swapNH.next(solution, n1); + swapEval(solution,n1); + n1.print(); +} +``` + +You can run the executable on the lesson 2 directory and see the output (the beginning). + +## 2. Indexed neighbordhoods (example with a shift operator) + +### Implementation +Three indexed neighborhoods are already defined in Paradiseo-MO. To use them you have to know the size of your neighborhoods and define a mapping that associates a neighbor from a known key, in your class neighbor. This neighbor must inherit from "moIndexNeighbor". + +### Example +In the mo/src/problems/permutation" directory, a neighbor for shift operator (moShiftNeighbor.h) is defined. In this class, the mapping is done in the method "translate". + +After inclusion useful types are defined for more lisibility: + +Define type of a shift neighbor +```c++ +typedef moShiftNeighbor shiftNeighbor; +``` +Define three different indexed neighborhoods for shift operator +```c++ +typedef moOrderNeighborhood orderShiftNeighborhood; +typedef moRndWithoutReplNeighborhood rndWithoutReplShiftNeighborhood; +typedef moRndWithReplNeighborhood rndWithReplShiftNeighborhood; +``` + +And in the "main" fonction, a shift neighbor and the three indexed neighborhoods are declared: +```c++ +shiftNeighbor n2; +orderShiftNeighborhood orderShiftNH(pow(vecSize-1, 2)); +rndWithoutReplShiftNeighborhood rndNoReplShiftNH(pow(vecSize-1, 2)); +rndWithReplShiftNeighborhood rndReplShiftNH(pow(vecSize-1, 2)); +``` + +Exploration of the neighborhoods is done like with a classical neighborhood. + +You can run the executable on the lesson 2 directory and see the output. + +## 3. Evaluation of neighbors + +There are three ways to evaluate a neighbor: + +1. Incremental evaluation +2. Full evaluation by modification +3. Full evaluation by copy + +In terms of performance, it is more efficient to use incremental evaluation and if it cannot be defined, full evaluation by modification is better than that one by copy. + +### Incremental evaluation +To implement an incremental evaluation, you have to create a class which inherits of "**moEval**". So you have to define the method: +```c++ +void operator()(EOT&, Neighbor&){ ... } +``` +EOT and Neighbor are respectively the templates for a solution and a neighbor. + +### Full evaluation +The two full evaluations are already defined in Paradiseo-MO. The full evaluation by modification applies the move on the initial solution, evaluates the obtained solution and affects the fitness value to the neighbor. Then the "moveBack" is applied to come back to the initial solution. On the other hand, the full evaluation by copy applies the move on a temporary copy of the solution, evaluates it and affects the fitness value to the neighbor. + +To use these evaluations, you need your classical full evaluation function ("eoEvalFunc") in the constructors: +```c++ +moFullEvalByCopy(eoEvalFunc& _eval) +moFullEvalByModif(eoEvalFunc& _eval) +``` + +Be carefull, if you want to use the class "moFullEvalByModif", your neighbor must be "backable" and so it has to inherit of the class "**moBackableNeighbor**" and consequently to have a method "moveBack". + +## 4. Exercise + +Try to define an indexed swap neighbor like in the file "moShiftNeighbor.h". Then explore and print the neighborhood randomly. \ No newline at end of file diff --git a/mo/tutorial/Lesson3/README.md b/mo/tutorial/Lesson3/README.md new file mode 100644 index 000000000..ea68ad686 --- /dev/null +++ b/mo/tutorial/Lesson3/README.md @@ -0,0 +1,110 @@ +# Lesson3 - How to use Simulated Annealing and Checkpointing +In this lesson, a simple simulated annealing is presented, using an order neighborhood based on a shift operator, to solve the Queen problem. Then, a checkpoint will be used to save some informations during the search. + +1. Simulating Annealing on the Queen problem. +2. Checkpointing +3. Avalaible statistics in MO +4. Exercise + +## 1. Simulating Annealing (example on the Queen problem) + +First you have to define the representation of a Queen, how to initialize and evaluate it. So you have to declare three classes: +```c++ +queenFullEval fullEval; +eoInitPermutation init(vecSize); +Queen solution1; +``` + +Then, you have to ramdomly intialize and evaluate the solution: +```c++ +init(solution1); +fullEval(solution1); +``` + +Let see the most simple constructor of a Simulated Annealing (in algo/moSA.h). You need three parameters: +* a neighborhood +* a full evaluation function (declared before) +* a neighbor's evaluation function +```c++ +moFullEvalByCopy shiftEval(fullEval); +rndShiftNeighborhood rndShiftNH(pow(vecSize-1, 2)); +``` + +You can now declare the Simulated Annealing: +```c++ +moSA localSearch1(rndShiftNH, fullEval, shiftEval); +``` +This simple constructor uses by default three components: +* moSimpleCoolingSchedule (with default parameters) +* moSolNeighborComparator +* moTrueContinuator + +More flexible constructors exist in which you can change these components. In the following, the "moTrueContinuator" is replaced by a "moCheckpoint". + +You can try this first algorithm with different problem sizes (use parameter file or the option --vecSize=X on command line to execute "testSimulatedAnnealing"). It prints the initial and final solution1. + +## 2. Checkpointing (example on the Queen problem) + +The class "moCheckpoint" inherits of the abstract class "moContinuator" and allows to incorporate one or many "moContinuator" classes (Composite pattern). It also allows to incorporate many "eoMonitor", "eoUpdater" and "moStatBase" classes. + +Here, an example of checkpointing is presented, including: +* a continuator returning always true (moTrueContinuator) +* a monitor saving information in a file (eoFileMonitor) +* an updater using the file monitor with a determinated frequency (moCounterMonitorSaver) +* a very simple statistical operator giving only the fitness of the current solution (moFitnessStat) + +First, you have to define the "moTrueContinuator" and build the "moCheckpoint": +```c++ +moTrueContinuator continuator; +moCheckpoint checkpoint(continuator); +``` + +Then, create the "moFitnessStat" and add it in the checkpoint: +```c++ +moFitnessStat fitStat; +checkpoint.add(fitStat); +``` + +Finally, create the "eoFileMonitor" to write fitness values in the file fitness.out and the "moCounterMonitorSaver" to use the file monitor only for each 100 iterations. +```c++ +eoFileMonitor monitor("fitness.out", ""); +moCounterMonitorSaver countMon(100, monitor); +checkpoint.add(countMon); +monitor.add(fitStat); +``` + +So you can create a Simulated Annealing with this checkpoint: +```c++ +moSA localSearch2(rndShiftNH, fullEval, shiftEval, coolingSchedule, solComparator, checkpoint); +``` + +Try this second algorithm with different problem sizes (use parameter file or the option --vecSize=X on command line to execute "testSimulatedAnnealing"). It prints the initial and final solution2 and you can see the evolution of fitness values in the file fitness.out (only 1 value each 100 iterations). + +## 3. Avalaible statistics + +A lot of statistics are avalaible to have informations during the search: + +* moCounterStat +* moMinusOneCounterStat +* moStatFromStat +* moFitnessStat +* moNbInfNeighborStat +* moNbSupNeighborStat +* moNeutralDegreeNeighborStat +* moSizeNeighborStat +* moNeighborhoodStat +* moDistanceStat +* moSolutionStat +* moBestSoFarStat +* moSecondMomentNeighborStat +* moMaxNeighborStat +* moMinNeighborStat +* moNeighborBestStat +* moNeighborFitnessStat +* moAverageFitnessNeighborStat +* moStdFitnessNeighborStat + +## 4. Exercise + +1. Try to add the cooling schedule parameters into the parameters file. Then, try the simulated annealing with different parameters to see theirs impacts on the search. +2. Add an existed operator (in continuator directory) to print the solution each 100 iterations. \ No newline at end of file diff --git a/mo/tutorial/Lesson4/README.md b/mo/tutorial/Lesson4/README.md new file mode 100644 index 000000000..c416fbd1a --- /dev/null +++ b/mo/tutorial/Lesson4/README.md @@ -0,0 +1,67 @@ +# How to use Tabu Search +In this lesson, a simple tabu search is presented, using an order neighborhood based on a shift operator, to solve the Queen problem. +1. Tabu Search on the Queen problem. +2. Exercise + +## 1. Tabu Search (example on the Queen problem) + +First you have to define the representation of a Queen, how to initialize and how to evaluate it. So you have to declare three classes: +```c++ +queenFullEval fullEval; +eoInitPermutation init(vecSize); +Queen sol1; +``` + +Then, you have to ramdomly intialize a solution: +```c++ +init(sol1); +fullEval(sol1); +``` + +Let see the most simple constructor of a Tabu Search (in mo/src/algo/moTS.h). You need five parameters: + +* a neighborhood +```c++ +orderShiftNeighborhood orderShiftNH(pow(vecSize-1, 2)); +``` +* a full evaluation function (declared before) +* a neighbor evaluation function* +```c++ +moFullEvalByCopy shiftEval(fullEval); +``` +* a time limit for the search (in seconds) +* a size for the tabu list + +You can now declare the Tabu Search: +```c++ +moTS localSearch1(orderShiftNH, fullEval, shiftEval, 2, 7); +// 2 is the time limit, 7 is the size of the tabu List +``` + +This simple constructor uses by default seven components: +* moTimeContinuator +* moNeighborComparator +* moSolNeighborComparator +* moNeighborVectorTabuList +* moDummyIntensification +* moDummyDiversification +* moBestImprAspiration + +More flexible constructors exist as you can change these components: +```c++ +moNeighborVectorTabuList tl(sizeTabuList,0); +moTS localSearch2(orderShiftNH, fullEval, shiftEval, 3, tl); +// 3 is the time limit +``` +In this one, the tabuList has been specified. +```c++ +moTS localSearch3(orderShiftNH, fullEval, shiftEval, + comparator, solComparator, continuator, tl, inten, div, asp); +``` +In this one, comparators, continuator, tabu list, intensification strategy, diversification strategy and aspiration criteria have been specified. + +You can test these three algorithms by changing problem sizes, time limit and the size of tabu list (use parameters file or the option --vecSize=X, --timeLimit=Y and --sizeTabuList=Z on command line to execute "testSimpleTS"). It prints the initial and final solutions. + +## 2. Exercise + +1. Try to implement and use a diversification strategy in 'testSimpleTS". You can also use a predifined strategy: moMonOpDiversification (in "memory" directory) \ No newline at end of file diff --git a/mo/tutorial/Lesson5/README.md b/mo/tutorial/Lesson5/README.md new file mode 100644 index 000000000..8a684df71 --- /dev/null +++ b/mo/tutorial/Lesson5/README.md @@ -0,0 +1,64 @@ +# How to use Iterated Local Search +In this lesson, an Iterated Local Search is presented. The Tabu Search of the Lesson 4 is used with an order neighborhood based on a shift operator, to solve the Queen problem. + +1. Iterated Tabu Search on the Queen problem. +2. Exercise + +## 1. Iterated Tabu Search (example on the Queen problem) + +As in Lesson 4, you have to define a Solution, the method to initialize and evaluate it. Then you have to define a Tabu Search. + +Declaration of the Tabu Search: +```c++ +moTS ts(orderShiftNH, fullEval, shiftEval, 1, 7); +``` + +To use a simple Iterated Local Search, a mutation operator is needed. So the swap mutation defined in EO is used: +```c++ +eoSwapMutation mut; +``` + +Now, a simple Iterated Tabu Search can be declared as follow: +```c++ +moILS localSearch1(ts, fullEval, mut, 3); +``` +This constructor has got 4 parameters: +1. a local search (ts) +2. a full evaluation function (fullEval) +3. a mutation operator (mut) +4. a number of iterations (3) + +**localSearch1** performs the Tabu Search 3 times. The first solution of each iteration(except the first one) is obtained by applying the mutation operator on the last visited solution. + +A constructor allows to specify the continuator. **_Be carefull_**, the continuator must be templatized by a "moDummyNeighbor": +```c++ +moIterContinuator > cont(4, false); +``` +The explorer of the Iterated local search don't use its own neighborhood. Here, the neighborhood of the Tabu Search is used. But to respect the conception, we create a "moDummyNeighbor" using as template for Iterated Local Search. + +An Iterated Tabu Search with this continuator can be declared as: +```c++ +moILS localSearch2(ts, fullEval, mut, cont); +``` + +A general constructor is available allowing to specify the perturbation operator and the acceptance criteria. First, you have to declare a perturbation operator: +```c++ +moMonOpPerturb perturb(mut, fullEval); +``` +And, the acceptance criteria: +```c++ +moSolComparator solComp; +moBetterAcceptCrit accept(solComp); +``` +Finally, the Iterated Local Search can be declared as: +```c++ +moILS localSearch3(ts, fullEval, cont, perturb, accept); +``` + +You can test these three algorithms by changing problem sizes(use parameter file or the option --vecSize=X on command line to execute "testILS"). It prints the initial and the final solutions. + +## 2. Exercise + +* Try to implement an Iterated Hill Climbing on the Queen problem with these caracteristics: + 1. Hill Climbing with a "moShiftNeighborhood" and a "moTrueContinuator" + 2. Iterated Local Search using a "moIterContinuator" and a "moNeighborhoodPerturb" with a "moSwapNeighborhood". \ No newline at end of file diff --git a/mo/tutorial/Lesson6/README.md b/mo/tutorial/Lesson6/README.md new file mode 100644 index 000000000..e8f4ba747 --- /dev/null +++ b/mo/tutorial/Lesson6/README.md @@ -0,0 +1,250 @@ +# How to perform a fitness analysis? + +![](multimodalFitnessLandscape.jpg) + +A lot of tools to perform the fitness landscapes analysis are defined in paradisEO-MO: +* Density Of States +* Fitness Distance Correlation +* Autocorrelation length and autocorrelation functions +* Sampling the local optima by adaptive walks +* Neutral degree distribution +* Evolvability of neutral networks by neutral walks +* Fitness Cloud + +With the same code (and effort ;-) ), you can make an apriori study of your problem with fitness landscapes analysis and use efficient solution-based metaheuristics. You can also make an aposteriori fitness landscapes analysis of your problem to explain why your metaheuristics works or not. + +This lesson will let you: +* Use the fitness analysis tools of MO library +* Learn to perform your own fitness landscapes analysis + +In lesson 1, you have learnt to define the fitness function. In lesson 2, you have learn to define a neighbor and a neighborhoods. This lesson will used those previous lessons. + +This tutorial is made to learn how to perform a fitness landscapes analysis with paradisEO-MO. It is not a course to learn fitness landscapes analysis. You can find some information about fitness landscapes analysis here: [tutorial GECCO 09 (pdf)](http://www.i3s.unice.fr/~verel/talks/tutorialFitnessLandscapes_gecco2009.pdf) or [tutorial WCCI-CEC 10 (pdf)](http://www.i3s.unice.fr/~verel/talks/tutorialCEC2010.pdf) + +## 1. I want to compute the Fitness Distance Correlation (FDC)! + +You can compute the FDC. From the "paradiseo-mo/build/tutorial/Lesson6" directory, type: +```shell +./fdc -V=20 -n=500 +``` + +Great! You have sample fitness and distance to global optimum of 500 random solutions on the oneMax problem (which maximizes the number of ones in the bit string) for the bit strings of size 20. On your output screen, you can see the fitness and distance of the first and last solution of the sample. For example: +```text +First values: +Fitness 8 +Distance 12 +Last values: +Fitness 6 +Distance 14 +``` + +In the file "out.dat", you have all the sample. First column is the fitness and the second column is the distance to global optimum of the 500 solutions. + +After you can compute the correlation coefficient with your best statistical software such as R (with this small script) or excel with this help (import data and correlation) or with this small awk script. + +I found -1 with my sample which means that it is very easy function, isn't it? + +## 2. The main principles of fitness landscapes analysis with MO + +The fitness landscapes analysis is based on a sampling of the search space. During this sampling, data are collected, and then some statistics can be computed to deduce the structure of the search space. + +The class to define a sampling is moSampling in the directory mo/src/sampling. All classes of the standard tools of fitness landscapes analysis inherit from this class (see documentation): +* moDensityOfStatesSampling : density of states (distribution of fitness values) +* moAutocorrelationSampling : autocorrelation length and functions +* moFDCsampling : fitness distance correlation +* moHillClimberSampling : adaptive walks +* moNeutralDegreeSampling : neutral degree +* moNeutralWalkSampling : evolvability of neutral networks +* moFitnessCloudSampling : evolvability of the operator, and the neighborhood + +The constructor of moSampling is: +```c++ +moSampling (eoInit< EOT > &_init, moLocalSearch< Neighbor > &_localSearch, moStat< EOT, ValueType > &_stat, bool _monitoring=true) +``` + +As usual in paradiseo, EOT is the typedef of the solution, and Neighbor is the typedef of the neighbor (see lesson 1). This constructor needs an initialization methods (see tutorial on paradiseo-eo), a local search which perform the sampling of the search space (see previous lessons to define it), and a object which able to compute a statistic. At each iteration of the local search, the given statistic is computed, and is saved if boolean monitoring is true. + +The statistics inherit from the class moStat. The include file can be found in mo/src/continuator directory. The pre-defined statistics are: +* moFitnessStat : the fitness of the current solution +* moDistanceStat : the distance between the current solution and a given solution +* moSolutionStat : the current solution +* moCounterStat : the number of iterations +* moBestSoFarStat : the best current solution found +* moNeighborBestStat : best fitness over k neighbors +* moNeighborhoodStat : to compute the statistics from the neighbors solutions : + * moAverageFitnessNeighborStat : average fitness in the neighborhood + * moStdFitnessNeighborStat : standard deviation of fitness + * moMaxNeighborStat : maximum fitness + * moMinNeighborStat : minimum fitness + * moSecondMomentNeighborStat : average and standard deviation + * moSizeNeighborStat : size of the neighborhood + * moNeutralDegreeNeighborStat : number of neighbors with equal fitness + * moNbInfNeighborStat : number of neighbors with lower fitness + * moNbSupNeighborStat : number of neighbor with higher fitness + +All those statistics can be used in the sampling. Of course you can define your own statistic class. Several statistics can be collected at each iteration: use the method add of the class moSampling to collect another statistic. + +For standard tools of fitness landscapes analysis, there is no need to give the sampling method, and the statistics objects. You only have to give which is specific to your problem such as the initialization method, the fitness function, the neighborhood, or the evaluation function of a neighbor. + +## 3. Browsing the code + +Please, open the file "mo/tutorial/Lesson6/fdc.cpp", and follow me in the code: + +### 1. The includes part: + +The general includes for the c++ stdlib streams: +```c++ +#include +#include +#include +#include +#include +``` + +This includes for eo which contains all include files of EO: +```c++ +#include +``` + +The first line to include the bit string representation defined in eo, and the second one to include the bit string neighbor representation. All classical problem-dependent part of MO are defined in the sub-directory "problems". How to define your representation is explained in EO tutorial, and how to design your neighbor is explained in the lesson 2. Here just use it. +```c++ +#include +#include +``` + +This includes the evaluation function of a solution (full evaluation). There is no evaluation function for the neighbor because there is no need in FDC. Some others tools such as autocorrelation neighbor evaluation is defined such as the lesson 1. +```c++ +#include +``` + +The fitness distance correlation is the correlation between the fitness of solution and the distance to global optimum (or at least to some best known solution). So, this include file uses the Hamming distance. +```c++ +#include +``` + +Now we can include the FDC tool. +```c++ +#include +``` + +### 2. The typedef part: + +EO can apply an evolutionary algorithm on any type of solution. So, all EO classes are parametrized by the type of solutions, and it is useful to use a synonym (with a typedef) of the solution's type. +MO can apply an local search algorithm on any type of solution and neighbor. So, for the same reason, all classes of MO are parametrized by the neighbor's type. In the neighbor class, the solution's type is defined. More precision on the neighbor design will be given in the lesson 2. +Here the solution representation is a bit string and the neighbor representation is related to a bit string solution and Hamming distance 1 (only 1 bit can be flipped), both using an "unsigned int" fitness value. +```c++ +typedef eoBit Indi; +typedef moBitNeighbor Neighbor; +``` + +### 3. Object definition part: + +Follows the main function "main_function" where all useful objects are defined.\\ +First, a code to parse the command line and a file. It gives the value of the random seed and the size of bit string. The lesson 3 of EO tutorial gives more precision on this code. Here we have only to understand that the variables "seed" and "vecSize" are initialized. +```c++ +eoParser parser(argc, argv); + +eoValueParam seedParam(time(0), "seed", "Random number seed", 'S'); +parser.processParam( seedParam ); +unsigned seed = seedParam.value(); + +// length of the bit string +eoValueParam vecSizeParam(20, "vecSize", "Genotype size", 'V'); +parser.processParam( vecSizeParam, "Representation" ); +unsigned vecSize = vecSizeParam.value(); + +// the number of solution sampled +eoValueParam solParam(100, "nbSol", "Number of random solution", 'n'); +parser.processParam( solParam, "Representation" ); +unsigned nbSol = solParam.value(); + +// the name of the output file +string str_out = "out.dat"; // default value +eoValueParam outParam(str_out.c_str(), "out", "Output file of the sampling", 'o'); +``` + +To seed the random seed (see lesson 1 of EO tutorial for more precision): +```c++ +rng.reseed(seed); +``` + +The definition the initialization of solutions is not defined is MO but in EO. The "eoInitFixedLength" is a class that makes a random intialization of bit string of a given length. Each bit is true with 1/2 rate. You can see the lesson 1 of EO tutorial lesson 1 for more precision. +```c++ +eoUniformGenerator uGen; +eoInitFixedLength random(vecSize, uGen); +``` + +The fitness function of the oneMax problem is the number of 1 in the bit string. It is already defined in MO: +```c++ +oneMaxFullEval fullEval; +``` + +The distance used is the classical Hamming distance: +```c++ +eoHammingDistance distance; +``` + +For this analysis, the best solution is needed: the solution with all 1s. +```c++ +Indi bestSolution(vecSize, true); // global optimum +``` + +All representation-dependent part is now defined, so the FDC sampling can be defined. The constructor needs the initialization, the fitness function, the distance used, the reference solution, and the size of the sample: +```c++ +moFDCsampling sampling(random, fullEval, distance, bestSolution, nbSol); +``` + +### 4. The execution of sampling part: + +Now apply your sampling as follows: +```c++ +sampling(); +``` + +This sampling uses the initialization method to define a pure random search, and at each iteration the fitness and the distance are computed. + +4. The export part: + +To export your sample into a file: +```c++ +sampling.fileExport(str_out); +``` + +The first column of the file is the fitness and the second the distance from the global optimum. + +Maybe you may want to read the data from your c++ code. So it is possible to export the data into a vector: +```c++ +const std::vector & fitnessValues = sampling.getValues(0); +const std::vector & distValues = sampling.getValues(1); +``` + +Note that the indexes of the statistics (here 0 and 1) are in the same order of the declaration with the constructor and the "add" method of moSampling. + +After you can use the vector as you want: +```c++ +std::cout << "Fitness " << fitnessValues[0] << std::endl; +std::cout << "First values:" << std::endl; +std::cout << "Distance " << distValues[0] << std::endl; + +std::cout << "Last values:" << std::endl; +std::cout << "Fitness " << fitnessValues[fitnessValues.size() - 1] << std::endl; +std::cout << "Distance " << distValues[distValues.size() - 1] << std::endl; + +``` + +Easy, isn't it? + +## 4. Others fitness landscapes tools + +The other tools can be used in the same way. For each tool, an example has been made. Please read the code of: + +* densityOfStates.cpp : density of states example +* autocorrelation.cpp : autocorrelation length and functions +* adaptiveWalks.cpp : sampling by hill-climbings, length of adaptative walks +* fdc.cpp : ;-) +* fitnessCloud.cpp : bivariate density of fitness of solutions and fitness of neighbors +* neutralDegree.cpp : number of neighbor with the same fitness +* neutralWalk.cpp : evolvability of the neutral networks +* sampling.cpp : general sampling method + +If you have some questions or remarks, please contact us! sebastien.verel aaattt unice.fr or member of the development team. \ No newline at end of file diff --git a/mo/tutorial/Lesson6/multimodalFitnessLandscape.jpg b/mo/tutorial/Lesson6/multimodalFitnessLandscape.jpg new file mode 100755 index 0000000000000000000000000000000000000000..ad3b52ce09369b311417fc897bd6f3558978b935 GIT binary patch literal 19455 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 Hjd#BT_^tD& literal 0 HcmV?d00001 diff --git a/mo/tutorial/Lesson7/README.md b/mo/tutorial/Lesson7/README.md new file mode 100644 index 000000000..5f493a130 --- /dev/null +++ b/mo/tutorial/Lesson7/README.md @@ -0,0 +1,60 @@ +# How to hybrid an evolutionary algorithm and a local search +In this lesson, a hybridization between an evolutionary algorithm(EA) and a local search is presented. It will be illustrated by an example on the Queen problem. Here, the hybridization consists in replacing the mutation operator of the EA by a first improvement hill climber. + +1. hybridization +2. Exercise + +## 1. Hybridization (example on the Queen problem) + +First, you have to define the represenation of a Queen, how to initialize and how to evaluate a population of solutions: +```c++ +queenFullEval fullEval; + +eoInitPermutation init(vecSize); + +eoPop pop; +Queen tmp; +for(unsigned int i=0; i<20; i++){ //population size is fixed to 20 + init(tmp); + fullEval(tmp); + pop.push_back(tmp); +} +``` + +As in previous lessons, a local search is declared (first improvement hill climber): +```c++ +moFullEvalByCopy shiftEval(fullEval); + +orderShiftNeighborhood orderShiftNH(pow(vecSize-1, 2)); + +moFirstImprHC hc(orderShiftNH, fullEval, shiftEval); +``` +To hybrid this local search with an EA, you just have to use it instead of a classical mutation: +```c++ +eoOrderXover cross; +eoSGATransform transform(cross, 0.3, hc, 0.7); // cross and mutation probabilities are fixed +``` + +Others components of the "eoEasyEA" have to be declared: +```c++ +eoGenContinue EAcont(50); //nb generations is fixed to 50 +eoDetTournamentSelect selectOne(2); //size of tournament is fixed to 2 +eoSelectMany select(selectOne, 1); //rate of selection is fixed to 1 +eoGenerationalReplacement repl; +``` +More details are available in EO lessons. + +Finally, the hybrid algorithm is declared as: +```c++ +eoEasyEA hybridAlgo(EAcont, fullEval, select, transform, repl); +``` +and should be applied on the population with: +```c++ +hybridAlgo(pop); +``` + +You can test this hybrid algorithm by changing problem size (use parameters file or the option --vecSize=X on command line to execute "hybridAlgo"). It prints the initial and final population. + +## 2. Exercise + +Try to use a hybridization at the checkpointing step rather than at the mutation step. You have to implement an "eoUpdater" which applies a local search. This updater should be added in a "eoCheckpoint". \ No newline at end of file