{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", " GENETIC ALGORITHMS (GAs) \n", "
\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
\n", "
\n", " Introduction " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A genetic algorithm is a search heuristic that is inspired by Charles Darwin’s theory of natural evolution. This algorithm reflects the process of natural selection where the fittest individuals are selected for reproduction in order to produce offspring of the next generation.\n", "\n", "The process of natural selection starts with the selection of fittest individuals from a population. They produce offspring which inherit the characteristics of the parents and will be added to the next generation. If parents have better fitness, their offspring will be better than parents and have a better chance of surviving. This process keeps on iterating and at the end, a generation with the fittest individuals will be found." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![Figure 1](GAFigure1.png)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
\n", "
\n", " Motivation " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Some difficult problems have real-world applications. Imagine that you are using your GPS Navigation system, and it takes a few minutes (or even a few hours) to compute the “optimal” path from the source to destination. Delay in such real-world applications is not acceptable and therefore a “good-enough” solution, which is delivered “fast” is what is required.\n", "A classic example of this representation is the traveling salesman problem (TSP). In this the salesman has to take a tour of all the cities, visiting each city exactly once and come back to the starting city. The total distance of the tour has to be minimized. The solution to this TSP is naturally an ordering or permutation of all the cities and therefore using a permutation representation makes sense for this problem. For example, for 5 cities there are 120 different solutions (5!=120) but if we have 10 cities, there are 3,628,800 possibilities.\n", "\n", "This notion can be applied to a search problem. We consider a set of solutions for a problem and select the set of best ones out of them.\n", "\n", "Genetic Algorithms are frequently used in:\n", "\n", " + Optimization. Genetic Algorithms are most commonly used in optimization problems wherein we have to maximize or minimize a given objective function value under a given set of constraints. \n", "\n", " + Economics. GAs are also used to characterize various economic models like the cobweb model, game theory equilibrium resolution, asset pricing, etc.\n", "\n", " + Parallelization. GAs also have very good parallel capabilities and prove to be very effective means in solving certain problems, and also provide a good area for research.\n", "\n", " + Vehicle routing problems. With multiple soft time windows, multiple depots and a heterogeneous fleet.\n", "\n", " + Robot Trajectory Generation. GAs have been used to plan the path which a robot arm takes by moving from one point to another.\n", "\n", " + Multimodal Optimization. GAs are obviously very good approaches for multimodal optimization in which we have to find multiple optimum solutions." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
\n", "
\n", "Strengths/Weaknesses " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", " Advantages\n", "\n", " + Does not require any derivative information (which may not be available for many real-world problems).\n", "\n", " + Is faster and more efficient as compared to the traditional methods.\n", "\n", " + Has very good parallel capabilities.\n", "\n", " + Provides a list of “good” solutions and not just a single solution.\n", "\n", " + Always gets an answer to the problem, which gets better over the time.\n", "\n", " + Useful when the search space is very large and there are a large number of parameters involved.\n", "\n", "\n", "
\n", " Limitations\n", "\n", " + GAs are not suited for all problems, especially problems which are simple and for which derivative information is available. Probably we don'tget the global optimum solution\n", " \n", " + Fitness value is calculated repeatedly which might be computationally expensive for some problems; in other words, \n", "\n", " + Being stochastic, there are no guarantees on the optimality or the quality of the solution.\n", "\n", " + If not implemented properly, the GA may not converge to the optimal solution." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
\n", "
\n", " Process " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Five phases are considered in a genetic algorithm.\n", "\n", " 1) Population initialization\n", " 2) Fitness function\n", " 3) Selection\n", " 4) Crossover\n", " 5) Mutation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![Figure 2](GAFigure2.png)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Initial Population**\n", "\n", "The process begins with a set of individuals which is called a Population. Each individual is a solution to the problem you want to solve. An individual is characterized by a set of parameters (variables) known as Genes. Genes are joined into a string to form a Chromosome (solution).\n", "\n", "**Fitness Function**\n", "\n", "The fitness function determines how fit an individual is (the ability of an individual to compete with other individuals). It gives a fitness score to each individual. The probability that an individual will be selected for reproduction is based on its fitness score.\n", "\n", "**Selection**\n", "\n", "The idea of selection phase is to select the fittest individuals and let them pass their genes to the next generation.\n", "\n", "Two pairs of individuals (parents) are selected based on their fitness scores. Individuals with high fitness have more chance to be selected for reproduction.\n", "\n", "**Crossover**\n", "\n", "Crossover is the most significant phase in a genetic algorithm. For each pair of parents to be mated, a crossover point is chosen at random from within the genes.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![Figure 3.](GAFigure3.png)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Mutation**\n", "\n", "In certain new offspring formed, some of their genes can be subjected to a mutation with a low random probability. This implies that some of the bits in the bit string can be flipped." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![Figure 4.](GAFigure4.png)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
\n", "
\n", " Some details to take into account " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The population size should not be kept very large as it can cause a GA to slow down, while a smaller population might not be enough for a good mating pool. Therefore, an optimal population size needs to be decided by trial and error.\n", "\n", "In a generational model, we generate ‘n’ off-springs, we can take the best off-springs and replace some individuals from the initial population or the entire population is replaced by the new one at the end of the iteration. What do you choose?\n", "\n", "For a new generation, is it better choose just all the best ones? Parent selection is very crucial to the convergence rate of the GA as good parents drive individuals to better and fitter solutions.\n", "\n", "However, care should be taken to prevent one extremely fit solution from taking over the entire population in a few generations, as this leads to the solutions being close to one another in the solution space thereby leading to a loss of diversity. Maintaining good diversity in the population is extremely crucial for the success of a GA. This taking up of the entire population by one extremely fit solution is known as premature convergence and is an undesirable condition in a GA.\n", "\n", "Some GAs employ Elitism, it means the current fittest member of the population is always propagated to the next generation, but keep in mind the diversity of the population should be maintained otherwise it might lead to premature convergence.\n", "\n", "In order to prevent premature convergence, there are several random methods for choosing parents: Roulette Wheel, Tournament, Stochastic Universal Sampling, or Random Selection. The fittest members have a preference for reproducing, but they shouldn't be the only ones.\n", "\n", "Crossover process can be achieved out splitting the chromosomes in two, three or uniform parts. \n", "\n", "Mutation is the part of the GA which is related to the “exploration” of the search space. It has been observed that mutation is essential to the convergence of the GA while crossover is not. We select one or more random bits and flip them.\n", "\n", "The Survivor Selection Policy determines which individuals are to be kicked out and which are to be kept in the next generation. It is crucial as it should ensure that the fitter individuals are not kicked out of the population, while at the same time diversity should be maintained in the population. See the comments in this video (5:30-9:10 min)\n" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "image/jpeg": "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\n", "text/html": [ "\n", " \n", " " ], "text/plain": [ "" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from IPython.display import YouTubeVideo\n", "YouTubeVideo(\"XP8R0yzAbdo\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The termination condition of a Genetic Algorithm is important in determining when a GA run will end. Usually, we keep one of the following termination conditions −\n", "\n", " + When there has been no improvement in the population for X iterations.\n", " + When we reach an absolute number of generations.\n", " + When the objective function value has reached a certain pre-defined value." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
\n", "
\n", " Summary" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "According to [1]:\n", "We use GA for discrete parameter optimization.\n", "\n", "It's good for combinatorial problems.\n", "\n", "They are slow.\n", "\n", "It's challenging to code, for example finding the right representations, the fitness function, etc." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
\n", "
\n", " Example" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Suppose that there is an equation a + 2b + 3c + 4d = 30, GA will be used to find the variables a, b, c, and d that satisfy the equation. First we should formulate the objective function, for this problem the function is f(a,b,c,d) = a + 2b + 3c + 4d -30. For simplicity we restrict to integers values between 0 and 30; in general, the variables a,b,c,d won't be necessary integers or have values in such domain. \n", "For the first step, we choose 50 individuals randomly." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The genes of an individual have the form [a,b,c,d]\n", "Initial Population:\n", "[10, 8, 8, 5]\n", "[21, 17, 23, 3]\n", "[22, 7, 22, 6]\n", "[8, 12, 17, 15]\n", "[8, 4, 18, 13]\n", "[17, 22, 18, 18]\n", "[29, 12, 8, 14]\n", "[23, 24, 17, 8]\n", "[3, 5, 15, 21]\n", "[29, 20, 0, 28]\n", "[19, 1, 1, 19]\n", "[9, 16, 16, 7]\n", "[18, 6, 29, 23]\n", "[26, 11, 0, 24]\n", "[7, 23, 20, 20]\n", "[8, 11, 26, 24]\n", "[21, 18, 24, 3]\n", "[27, 9, 28, 27]\n", "[18, 20, 26, 15]\n", "[7, 23, 5, 6]\n", "[12, 16, 17, 20]\n", "[24, 26, 6, 25]\n", "[9, 12, 9, 24]\n", "[7, 11, 26, 22]\n", "[25, 23, 15, 21]\n", "[2, 20, 19, 1]\n", "[18, 25, 0, 8]\n", "[12, 8, 21, 25]\n", "[11, 20, 15, 2]\n", "[16, 7, 5, 5]\n", "[21, 2, 12, 3]\n", "[8, 24, 6, 16]\n", "[28, 29, 4, 26]\n", "[12, 17, 24, 15]\n", "[10, 22, 19, 17]\n", "[0, 23, 5, 8]\n", "[8, 25, 23, 19]\n", "[17, 14, 12, 9]\n", "[8, 27, 8, 19]\n", "[6, 26, 29, 23]\n", "[19, 14, 2, 10]\n", "[28, 7, 7, 17]\n", "[25, 5, 10, 25]\n", "[23, 3, 3, 11]\n", "[0, 12, 4, 13]\n", "[4, 9, 25, 16]\n", "[27, 17, 11, 15]\n", "[4, 3, 0, 16]\n", "[10, 17, 15, 17]\n", "[11, 2, 26, 4]\n" ] } ], "source": [ "\n", "import random\n", "import math\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "\n", "def make_population(population_size, range_values):\n", " #We first start the population randomly\n", " population = []\n", " for i in range(population_size):\n", " p = [random.randrange(0,range_values,1), random.randrange(0,range_values,1), \n", " random.randrange(0,range_values,1), random.randrange(0,range_values,1)]\n", " population.append(p)\n", " return population\n", "\n", "\n", "range_values = 500\n", "population_size = 50\n", "number_iterations = 4000\n", "percentage_mutations = .25\n", "\n", "population = make_population(population_size, range_values)\n", "print('The genes of an individual have the form [a,b,c,d]')\n", "print('Initial Population:')\n", "_ = [print(x) for x in population]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we evaluate the population in the target function and select the top 30% members and 20% of the remaining ones. We take the 30% best chromosomes and 20% from the others chromosomes in order to avoid elithism. \n" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Selected: 22 \n", "\n", "[16, 7, 5, 5] has fitness = 35.0\n", "[10, 8, 8, 5] has fitness = 40.0\n", "[21, 2, 12, 3] has fitness = 43.0\n", "[4, 3, 0, 16] has fitness = 44.0\n", "[23, 3, 3, 11] has fitness = 52.0\n", "[0, 12, 4, 13] has fitness = 58.0\n", "[7, 23, 5, 6] has fitness = 62.0\n", "[0, 23, 5, 8] has fitness = 63.0\n", "[19, 14, 2, 10] has fitness = 63.0\n", "[19, 1, 1, 19] has fitness = 70.0\n", "[18, 25, 0, 8] has fitness = 70.0\n", "[2, 20, 19, 1] has fitness = 73.0\n", "[11, 20, 15, 2] has fitness = 74.0\n", "[11, 2, 26, 4] has fitness = 79.0\n", "[9, 16, 16, 7] has fitness = 87.0\n", "[3, 5, 15, 21] has fitness = 112.0\n", "[27, 17, 11, 15] has fitness = 124.0\n", "[9, 12, 9, 24] has fitness = 126.0\n", "[17, 22, 18, 18] has fitness = 157.0\n", "[18, 6, 29, 23] has fitness = 179.0\n", "[18, 20, 26, 15] has fitness = 166.0\n", "[29, 12, 8, 14] has fitness = 103.0\n" ] } ], "source": [ "\n", "\n", "def fitness(person):\n", " return math.fabs( person[0]+person[1]*2+person[2]*3+person[3]*4 -30)\n", "\n", "# Select 30% of total population from the top performers \n", "first_group = ordered_population[:int(population_size*'fill here with the correct value' )]\n", "other = ordered_population[int(population_size*.3):]\n", "\n", "# select 20% of total population from the remaining people\n", "second_group = random.sample(other, int(population_size*'fill here with the correct value'))\n", "\n", "# create the new population\n", "selection = first_group+second_group\n", "print(f\"top value of fitness: {fitness(ordered_population[0])}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "Crossover:We create new members with 50% chromosomes from the mother side and 50% from the father side." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "7 new people: \n", " [[0, 23, 5, 6], [18, 25, 2, 10], [10, 8, 11, 15], [9, 16, 1, 19], [0, 23, 0, 8], [10, 8, 15, 21], [4, 3, 5, 6]]\n" ] } ], "source": [ "#make crossover\n", "def crossover(selection, population_size):\n", " children = []\n", " number_inmigrants = int( population_size*'fill here with the correct value') #inmigration allows for more diversity\n", " population_current_size = len(selection)\n", " for i in range(population_size-population_current_size-number_inmigrants):\n", " father,mother = random.choices(selection, k=2)\n", " child = 'fill here with the correct value' #how do you mixes the genes?\n", " children.append(child)\n", " return children\n", " \n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the croosover, new elements are made, but the new generation process is not completed until the mutation step. For this example the third and fourth genes were mutated on 10% of the children." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "mutants: [[0, 23, 6, 5]]\n", "our new population has size: 29\n" ] } ], "source": [ "#make mutation\n", "\n", "def mutation(children=[]):\n", " #\n", " new_kids = []\n", " for child in children:\n", " mutant = 'fill here with the correct value' #how do you mutate the genes?\n", " new_kids.append(mutant) \n", " return new_kids" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "With the new elements the process is repeated: evaluation, selection, crossover and mutation. The iteration process can be achived until it find the optimized solution (\"while\" loop) or delimitated for a specific number (\"for\" loop). " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " " ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Initial population statistics: number of people 50 example [295, 0, 464, 97] \n", "top performance 889.0 worst performance 4100.0\n", "top performance 616.0 worst performance 3665.0\n", "top performance 355.0 worst performance 3954.0\n", "top performance 225.0 worst performance 3948.0\n", "top performance 129.0 worst performance 4107.0\n", "top performance 105.0 worst performance 3216.0\n", "top performance 95.0 worst performance 3266.0\n", "top performance 87.0 worst performance 3726.0\n", "top performance 38.0 worst performance 3782.0\n", "top performance 15.0 worst performance 4266.0\n" ] }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "# -*- coding: utf-8 -*-\n", "\"\"\"\n", "Find a,b,c,d that satisfy:\n", "\n", "a+2b+3c+4d=30\n", "\"\"\"\n", "\n", "import random\n", "import math\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "\n", "def make_population(population_size, range_values):\n", " #We first start the population randomly\n", " population = []\n", " for i in range(population_size):\n", " p = [random.randrange(0,range_values,1), random.randrange(0,range_values,1), \n", " random.randrange(0,range_values,1), random.randrange(0,range_values,1)]\n", " population.append(p)\n", " return population\n", " \n", "\n", "def fitness(person):\n", " return math.fabs( person[0]+person[1]*2+person[2]*3+person[3]*4 -30)\n", "\n", "\n", "def crossover(selection, population_size):\n", " children = []\n", " number_inmigrants = int(.1* population_size)\n", " population_current_size = len(selection)\n", " for i in range(population_size-population_current_size-number_inmigrants):\n", " father,mother = random.choices(selection, k=2)\n", " child = father[:2]+mother[2:]\n", " children.append(child)\n", " return children\n", " \n", "\n", "def mutation(children=[]):\n", " #\n", " new_kids = []\n", " for child in children:\n", " mutant = child[::-1]\n", " new_kids.append(mutant) \n", " return new_kids\n", "\n", "\n", "\n", "\n", "if __name__ == '__main__':\n", " # create a random population\n", " range_values = 500\n", " population_size = 50\n", " number_iterations = 4000\n", " percentage_mutations = .25\n", " population = make_population(population_size, range_values)\n", " solutions = []\n", " print(f\"Initial population statistics: number of people {population_size} example {population[-1]} \") \n", " X=[]\n", " Y=[]\n", " data=[]\n", " \n", " counter = 1\n", " old = 1000000\n", " while counter Homework\n", "\n", "\n", "Modify the GA to find a solution to the equation $x^3+y^3+z^3=d^3$ where $x,y,z,d>0$ are integers smaller than 60." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Advance Activity \n", "\n", "You can implement GA on the contest https://www.codingame.com/ide/puzzle/mean-max " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " References " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "+ Genetic Algorithms in Search, Optimization and Machine Learning by David E. Goldberg.\n", "\n", "+ Genetic Algorithms + Data Structures = Evolutionary Programs by Zbigniew Michalewicz.\n", "\n", "+ Practical Genetic Algorithms by Randy L. Haupt and Sue Ellen Haupt.\n", "\n", "+ Multi-Objective Optimization using Evolutionary Algorithms by Kalyanmoy Deb.\n", "\n", "[1]\n", "http://www.cs.northwestern.edu/~pardo/courses/eecs349/lectures.php\n", "\n", "[2] https://www.tutorialspoint.com/genetic_algorithms" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![Figure 5.](GAFigure5.png)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.12" } }, "nbformat": 4, "nbformat_minor": 2 }