{ "cells": [ { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "# Lab 8: Evolutionary computation\n", "\n", "### Consider the following example:\n", "\n", "Determine the minimum of the function $f(x)= x_1^2+...+x_n^2$ with $x_i \\in [-5.12, 5.12]$, $i \\in \\overline{(1, n)}$\n", "\n", "We have an example of steady state genetic algorithm with: representation an array of real numbers; 100 individuals; crossover $$child = \\alpha \\cdot (parent1 - parent2) + parent2 ;$$ mutation - reinitialise on a random position the individual's value." ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Result: The detected minimum point after 10000 iterations is f(-0.00 -0.00) = 0.00\n" ] } ], "source": [ "\n", "\n", "from random import randint, random\n", "from operator import add\n", "from math import cos, pi\n", "\n", "\n", "def individual(length, vmin, vmax):\n", " '''\n", " Create a member of the population - an individual\n", "\n", " length: the number of genes (components)\n", " vmin: the minimum possible value \n", " vmax: the maximum possible value \n", " '''\n", " return [ (random()*(vmax-vmin)+vmin) for x in range(length) ]\n", " \n", "def population(count, length, vmin, vmax):\n", " \"\"\"\n", " Create a number of individuals (i.e. a population).\n", "\n", " count: the number of individuals in the population\n", " length: the number of values per individual\n", " vmin: the minimum possible value \n", " vmax: the maximum possible value \n", " \"\"\"\n", " return [ individual(length, vmin, vmax) for x in range(count) ]\n", "\n", "def fitness(individual):\n", " \"\"\"\n", " Determine the fitness of an individual. Lower is better.(min problem)\n", " For this problem we have the Rastrigin function\n", " \n", " individual: the individual to evaluate\n", " \"\"\"\n", " n=len(individual)\n", " f=0;\n", " for i in range(n):\n", " f=f+individual[i]*individual[i]\n", " return f\n", " \n", "def mutate(individual, pM, vmin, vmax): \n", " '''\n", " Performs a mutation on an individual with the probability of pM.\n", " If the event will take place, at a random position a new value will be\n", " generated in the interval [vmin, vmax]\n", "\n", " individual:the individual to be mutated\n", " pM: the probability the mutation to occure\n", " vmin: the minimum possible value \n", " vmax: the maximum possible value\n", " '''\n", " if pM > random():\n", " p = randint(0, len(individual)-1)\n", " individual[p] = random()*(vmax-vmin)+vmin\n", " return individual\n", " \n", "def crossover(parent1, parent2):\n", " '''\n", " crossover between 2 parents\n", " '''\n", " child=[]\n", " alpha=random()\n", " for x in range(len(parent1)):\n", " child.append(alpha*(parent1[x]-parent2[x])+parent2[x])\n", " return child\n", "\n", "def iteration(pop, pM, vmin, vmax):\n", " '''\n", " an iteration\n", "\n", " pop: the current population\n", " pM: the probability the mutation to occure\n", " vmin: the minimum possible value \n", " vmax: the maximum possible value\n", " '''\n", " i1=randint(0,len(pop)-1)\n", " i2=randint(0,len(pop)-1)\n", " if (i1!=i2):\n", " c=crossover(pop[i1],pop[i2])\n", " c=mutate(c, pM, vmin, vmax)\n", " f1=fitness(pop[i1])\n", " f2=fitness(pop[i2])\n", " '''\n", " the repeated evaluation of the parents can be avoided\n", " if next to the values stored in the individuals we \n", " keep also their fitnesses \n", " '''\n", " fc=fitness(c)\n", " if(f1>f2) and (f1>fc):\n", " pop[i1]=c\n", " if(f2>f1) and (f2>fc):\n", " pop[i2]=c\n", " return pop\n", "\n", "def main(noIteratii=10000):\n", " #PARAMETERS:\n", " \n", " #population size\n", " dimPopulation = 100\n", " #individual size\n", " dimIndividual = 2\n", " #the boundries of the search interval\n", " vmin = -5.12\n", " vmax = 5.12\n", " #the mutation probability\n", " pM=0.01\n", " \n", " P = population(dimPopulation, dimIndividual, vmin, vmax)\n", " for i in range(noIteratii):\n", " P = iteration(P, pM, vmin, vmax)\n", "\n", " #print the best individual\n", " graded = [ (fitness(x), x) for x in P]\n", " graded = sorted(graded)\n", " result=graded[0]\n", " fitnessOptim=result[0]\n", " individualOptim=result[1]\n", " print('Result: The detected minimum point after %d iterations is f(%3.2f %3.2f) = %3.2f'% \\\n", " (noIteratii,individualOptim[0],individualOptim[1], fitnessOptim) )\n", " \n", "main()" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Exercise 1: Construct a similar algorithm to the one provided as an example for the Bukin function N.6 (search the internet for this function).\n" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Result: The detected minimum point after 10000 iterations is f(-9.81 0.96) = 0.00\n", "0.0\n" ] } ], "source": [ "# your code here\n", "\n", "\n", "from random import randint, random\n", "from operator import add\n", "from math import cos, pi\n", "\n", "\n", "def individual():\n", " return [ (random()*(-5+15)-15), (random()*(3+3)-3)]\n", " \n", "def population(count):\n", " return [ individual() for x in range(count) ]\n", "\n", "def fitness(individual):\n", " return (100 *((abs(individual[1] - 0.01*(individual[0]**2)))**(1/2))) + (0.01 * abs(individual[0] + 10))\n", " \n", "def mutate(individual, pM): \n", " if pM > random():\n", " p = randint(0, 1)\n", " if p == 0:\n", " individual[0] = random()*(-5+15)-15\n", " else:\n", " individual[1] = random()*(3+3)-3\n", " return individual\n", " \n", "def crossover(parent1, parent2):\n", " child=[]\n", " alpha=random()\n", " for x in range(len(parent1)):\n", " child.append(alpha*(parent1[x]-parent2[x])+parent2[x])\n", " return child\n", "\n", "def iteration(pop, pM):\n", " i1=randint(0,len(pop)-1)\n", " i2=randint(0,len(pop)-1)\n", " if (i1!=i2):\n", " c=crossover(pop[i1],pop[i2])\n", " c=mutate(c, pM)\n", " f1=fitness(pop[i1])\n", " f2=fitness(pop[i2])\n", " fc=fitness(c)\n", " if(f1>f2) and (f1>fc):\n", " pop[i1]=c\n", " if(f2>f1) and (f2>fc):\n", " pop[i2]=c\n", " return pop\n", "\n", "def main(noIteratii=10000):\n", " #PARAMETERS:\n", " \n", " #population size\n", " dimPopulation = 100\n", " #the mutation probability\n", " pM=0.01\n", " \n", " P = population(dimPopulation)\n", " for i in range(noIteratii):\n", " P = iteration(P, pM)\n", "\n", " #print the best individual\n", " graded = [ (fitness(x), x) for x in P]\n", " graded = sorted(graded)\n", " result=graded[0]\n", " fitnessOptim=result[0]\n", " individualOptim=result[1]\n", " print('Result: The detected minimum point after %d iterations is f(%3.2f %3.2f) = %3.2f'% \\\n", " (noIteratii,individualOptim[0],individualOptim[1], fitnessOptim) )\n", " print(fitness((-10,1)))\n", "main()" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Consider the knapsack problem:\n", "\n", "Consider a Knapsack with a total volum equal with $V_{max}$.\n", "\n", "There are $n$ objects, with values $(p_i)_{n}$ and volumes $(v_i)_n$.\n", "\n", "Solve this problem using a generationist Genetic Algorithm, with a binary representation.\n", "\n", "Exercise 2: Initialization\n", "Objective: Implement the initialization step of a genetic algorithm." ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[0 1 0 0 1 1 1 0]\n", " [0 1 0 1 0 1 0 0]\n", " [0 1 0 1 0 1 0 1]\n", " [1 0 0 0 0 0 0 1]\n", " [0 1 0 1 0 1 1 1]\n", " [0 1 0 1 0 1 1 1]\n", " [1 1 0 0 1 1 0 0]\n", " [1 0 0 0 0 0 1 0]\n", " [1 0 0 1 0 0 1 0]\n", " [1 1 1 1 0 0 0 0]]\n" ] } ], "source": [ "import random\n", "import numpy as np\n", "\n", "def individual(chromosome_length):\n", " return np.array([randint(0,1) for _ in range(chromosome_length)])\n", "\n", "def initialize_population(population_size, chromosome_length):\n", " # generate random a population with population_size number of individuals\n", " # each individual with the size chromosome_length\n", " # IN: population_size, chromosome_length\n", " # OUT: population\n", " return np.array([individual(chromosome_length) for _ in range(population_size)])\n", " # your code here\n", "\n", "\n", "\n", "\n", "# Test the initialization step\n", "population_size = 10\n", "chromosome_length = 8\n", "weights = np.array([1, 4, 5, 7, 3, 2, 4 ,1])\n", "values = np.array([2, 3, 1, 4, 2, 3, 4, 5])\n", "limit = 14\n", "population = initialize_population(population_size, chromosome_length)\n", "print(population)\n" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Exercise 3: Fitness Evaluation\n", "\n", "Objective: Implement the fitness evaluation step of a genetic algorithm." ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[12 10 15 7 0 0 10 6 10 0]\n" ] } ], "source": [ "def evaluate_fitness(population):\n", " # evaluate the fitness of each individual in the population\n", " # IN: population\n", " # OUT: fitness_scores\n", " # your code here\n", " total_weights = (weights * population).sum(axis=1)\n", " scores = (values * population).sum(axis=1)\n", " scores[total_weights > limit] = 0\n", " return scores\n", " \n", "# Test the fitness evaluation step\n", "fitness_scores = evaluate_fitness(population)\n", "print(fitness_scores)\n" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Exercise 4: Selection\n", "\n", "Objective: Implement the selection step of a genetic algorithm." ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[0 1 0 1 0 1 0 0]\n", " [0 1 0 1 0 1 0 1]]\n" ] } ], "source": [ "def select_parents(population, fitness_scores):\n", " # select two parents from the population based on the fitness - \n", " # the better the fitness, the higher the chance to be selected\n", " # IN: population, fitness_scores\n", " # OUT: selected_parents\n", " # your code here\n", " probs = ((fitness_scores + 1) / (fitness_scores + 1).sum())\n", " indexes = np.random.choice(population.shape[0], size = 2, replace=False, p=probs)\n", " return population[indexes]\n", " \n", "# Test the selection step\n", "parents = select_parents(population, fitness_scores)\n", "print(parents)\n" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Exercise 5: Crossover\n", "\n", "Objective: Implement the crossover step of a genetic algorithm." ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0. 1. 0. 1. 0. 1. 0. 1.]\n" ] } ], "source": [ "def crossover(parents):\n", " # create new offspring by combining the parents\n", " # IN: parents\n", " # OUT: offspring\n", "\n", " # your code here\n", " offspring = np.zeros((parents.shape[1],))\n", " for i in range(parents.shape[1]):\n", " if parents[0][i] == parents[1][i]:\n", " offspring[i] = parents[0][i]\n", " else:\n", " offspring[i] = random.randint(0, 1)\n", " return offspring\n", "\n", "\n", "# Test the crossover step\n", "offspring = crossover(parents)\n", "print(offspring)\n" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Exercise 6: Mutation\n", "\n", "Objective: Implement the mutation step of a genetic algorithm." ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0]\n" ] } ], "source": [ "def mutate(chromosome, mutation_rate):\n", " # mutate the chromosome by randomly flipping bits\n", " # IN: chromosome, mutation_rate\n", " # OUT: mutated_chromosome\n", "\n", " # your code here\n", " if random.random() <= mutation_rate:\n", " for i in range(len(chromosome)):\n", " chromosome[i] = random.randint(0, 1)\n", " return chromosome\n", "\n", "\n", "# Test the mutation step\n", "mutation_rate = 0.1\n", "mutated_offspring = [mutate(child, mutation_rate) for child in offspring]\n", "print(mutated_offspring)\n" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Exercise 7: Complete Genetic Algorithm\n", "\n", "Objective: Combine all the steps of a genetic algorithm to solve a specific problem." ] }, { "cell_type": "code", "execution_count": 56, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[1 1 0 0 0 1 1 1]\n", " [1 1 0 0 0 1 1 1]\n", " [1 1 0 0 0 1 1 1]\n", " [1 1 0 0 0 1 1 1]\n", " [1 1 0 0 0 1 1 1]\n", " [1 1 0 0 0 1 1 1]\n", " [1 1 0 0 0 1 1 1]\n", " [1 1 0 0 0 1 1 1]\n", " [1 1 0 0 0 1 1 1]\n", " [1 1 0 0 0 1 1 1]]\n" ] } ], "source": [ "def genetic_algorithm(population_size, chromosome_length, generations, mutation_rate):\n", " \n", " # complete genetic algorithm\n", " # IN: population_size, chromosome_length, generations, mutation_rate\n", " # OUT: population\n", "\n", "\n", " # initialize the population\n", " population = initialize_population(population_size, chromosome_length)\n", " # your code here\n", " \n", "\n", " for _ in range(generations):\n", " # Fitness evaluation\n", " # your code here\n", " fitnesses = evaluate_fitness(population)\n", " \n", " # Selection\n", " \n", " # your code here\n", " parents = select_parents(population, fitnesses)\n", "\n", " # Crossover\n", "\n", " # your code here\n", " child = crossover(parents)\n", "\n", " # Mutation\n", " \n", " # your code here\n", " mutated_child = mutate(child, mutation_rate)\n", "\n", " # Replace the population with the new generation\n", " \n", " # your code here\n", " minimum = fitnesses.min()\n", " for i in range(fitnesses.shape[0]):\n", " if minimum == fitnesses[i]:\n", " population[i] = mutated_child\n", " break\n", "\n", " return population\n", "\n", "# Test the complete genetic algorithm\n", "population_size = 10\n", "chromosome_length = 8\n", "generations = 100\n", "mutation_rate = 0.1\n", "\n", "final_population = genetic_algorithm(population_size, chromosome_length, generations, mutation_rate)\n", "print(final_population)\n" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Exercise 8: Extract the result from the final population\n", "\n", "Objective: Get the best individual from the final population.\n" ] }, { "cell_type": "code", "execution_count": 57, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Maximum is 17\n", "Chosen values [2 3 0 0 0 3 4 5] with weights [1 4 0 0 0 2 4 1]\n" ] } ], "source": [ "# determine the best individual from the final population and print it out\n", "\n", "# your code here\n", "\n", "fitnesses = evaluate_fitness(final_population)\n", "maximum = fitnesses.max()\n", "print(f\"Maximum is {maximum}\")\n", "for i in range(0, fitnesses.shape[0]):\n", " if fitnesses[i] == maximum:\n", " print(f\"Chosen values {final_population[i] * values} with weights {final_population[i] * weights}\")\n", " break" ] } ], "metadata": { "kernel_info": { "name": "python" }, "kernelspec": { "display_name": "Python 3", "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.12.2" }, "nteract": { "version": "nteract-front-end@1.0.0" }, "orig_nbformat": 4 }, "nbformat": 4, "nbformat_minor": 2 }