├── README.md ├── Workshop-Genetic-Algorithm.pdf ├── geneticAlgorithm.py └── solution └── solution-geneticAlgorithm.py /README.md: -------------------------------------------------------------------------------- 1 | # Workshop Genetic Algorithm - Intelligence Artificial :computer: 2 | 3 | ## Table of Contents 4 | 5 | 1. [Introduction](#introduction-dart) 6 | 2. [Requirements](#requirements-books) 7 | 3. [Workshop Content](#workshop-content-bulb) 8 | 4. [Contact](#contact-telephone_receiver) 9 | 10 | ## Introduction :dart: 11 | 12 | Artificial intelligence is one of the most exciting topics in computer science today. The following workshop session aims to give you a general understanding of how genetic algorithm works, its benefits and limitations, and how to implement it in your own A.I. projects. 13 | 14 | ## Requirements :books: 15 | 16 | - Python 3.8 -> Install python 3.8 [here](https://www.w3computing.com/python/installing-python-windows-macos-linux/) 17 | 18 | ## Workshop Content :bulb: 19 | 20 | The workshop is divided into 3 parts: 21 | 22 | - **Part 1**: Introduction and Understanding Genetic Algorithm 23 | - **Part 2**: Genetic Algorithm Development and Optimization 24 | - **Part 3**: Genetic Algorithm Implementation in different A.I. projects 25 | 26 | **You will find the content of all these parts in the pdf [here](https://github.com/Mitix-EPI/WorkShop-Genetic-Algorithm/blob/master/Workshop-Genetic-Algorithm.pdf)** 27 | 28 | ## Contact :telephone_receiver: 29 | 30 | If you have any question about the algorithm or the code, you can contact me directly on [Discord](https://discord.com/users/501067187793166365) or via [e-mail](alexandre.juan@epitech.eu). -------------------------------------------------------------------------------- /Workshop-Genetic-Algorithm.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mitix-EPI/WorkShop-Genetic-Algorithm/d8e5d2227c174ad1bef2856d661aea7fd384e1f6/Workshop-Genetic-Algorithm.pdf -------------------------------------------------------------------------------- /geneticAlgorithm.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3.8 2 | 3 | from typing import List, Tuple 4 | import random 5 | import sys 6 | 7 | VectorStr = List[float] # VectorStr is the population 8 | goal = "" 9 | 10 | # Check if the solution is in the population 11 | def checkSolutionInVectorStr(arrayStr: VectorStr) -> bool: 12 | pass 13 | 14 | # Swap two characters in a string 15 | def swapTwoRandomCharacterInString(str: str) -> str: 16 | pass 17 | 18 | # Change one character randomly 19 | def changeRandomlyOneCharacter(str: str) -> str: 20 | pass 21 | 22 | # Create mutation with a probability of 10% 23 | # A mutation is a random modification of the string 24 | # It can be a swap of two characters, a change of one character or a random character, a revert string etc. per example 25 | def mutationOfTenPercent(str: str) -> str: 26 | pass 27 | 28 | # dictionnary is a dictionnary with the string (word) as key and the fitness as value 29 | # Return a tuple with both words with highest fitness 30 | def getTwoStringWithHighestFitness(dictionnary: dict) -> Tuple[str, str]: 31 | pass 32 | 33 | # Get all possibilities of crossing over two strings 34 | # Generate population with 'all possibilities' of crossing over two strings 35 | # For example: if the two strings are "abc" and "def" 36 | # The possibilities are: 'ade' or 'fab' or 'cde' or 'bdf' etc. 37 | def getAllPossibilitiesOfCrossingOverTwoStrings(str1: str, str2: str) -> VectorStr: 38 | pass 39 | 40 | # Create a string with random characters with a length of len 41 | def createStringWithRandomChars(len: int) -> str: 42 | pass 43 | 44 | # Initial population 45 | # Generate a population with a size of arrLength 46 | def initPopulation(arrLength: int) -> VectorStr: 47 | pass 48 | 49 | # Calc the score of the string compared to the goal 50 | # The score is the number of characters that are the same per example 51 | def fitnessFunction(str: str) -> int: 52 | pass 53 | 54 | # Calculate fitness for each string 55 | # Generate a dictionnary with the string/word as key and the fitness as value 56 | def createDictionnaryWithFitness(arrayStr: VectorStr) -> dict: 57 | pass 58 | 59 | # Main function 60 | # Return the final population 61 | def GeneticAlgorithm() -> VectorStr: 62 | pass 63 | # Initial population 64 | # Compute fitness for each string 65 | # Until the population has converged to the goal 66 | # Select two strings with the highest fitness 67 | # Create a new population with all possibilities of crossing over two strings 68 | # Mutate the new population 69 | # Compute fitness for each string 70 | # Display final population 71 | 72 | # Check if string has only alphabetic characters 73 | def hasOnlyAlphabeticCharactersInLowerCase(str: str) -> bool: 74 | return str.isalpha() and str.islower() 75 | 76 | if __name__ == "__main__": 77 | if (len(sys.argv) == 2): 78 | if (hasOnlyAlphabeticCharactersInLowerCase(sys.argv[1])): 79 | goal = sys.argv[1] 80 | print("The goal : " + str(goal)) 81 | GeneticAlgorithm() 82 | exit(0) 83 | else: 84 | print("Please enter a string composed only with characters in lower case.") 85 | exit(84) 86 | else: 87 | print("Please enter the goal as the first argument") 88 | exit(84) 89 | -------------------------------------------------------------------------------- /solution/solution-geneticAlgorithm.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3.8 2 | 3 | from typing import List, Tuple 4 | import random 5 | import sys 6 | 7 | VectorStr = List[float] # VectorStr is the population 8 | goal = "" 9 | 10 | # Check if the solution is in the population 11 | def checkSolutionInVectorStr(arrayStr: VectorStr) -> bool: 12 | for str in arrayStr: 13 | if (str == goal): 14 | return True 15 | return False 16 | 17 | # Swap two characters in a string 18 | def swapTwoRandomCharacterInString(str: str) -> str: 19 | i: int = random.randint(0, len(str) - 1) 20 | j: int = random.randint(0, len(str) - 1) 21 | arr = list(str) 22 | arr[i], arr[j] = arr[j], arr[i] 23 | return "".join(arr) 24 | 25 | # Change one character randomly 26 | def changeRandomlyOneCharacter(str: str) -> str: 27 | i: int = random.randint(0, len(str) - 1) 28 | arr = list(str) 29 | arr[i] = chr(random.randint(97, 122)) 30 | return "".join(arr) 31 | 32 | # Create Mutation with a probability of 10% 33 | # You can upgrade this function to mutate with differents methods 34 | def mutationOfTenPercent(str: str) -> str: 35 | if (random.random() < 0.1): 36 | if (random.random() < 0.5): 37 | return changeRandomlyOneCharacter(str) 38 | else: 39 | return swapTwoRandomCharacterInString(str) # Change one character randomly 40 | else: 41 | return str 42 | 43 | # Get two strings with highest fitness 44 | def getTwoStringWithHighestFitness(dictionnary: dict) -> Tuple[str, str]: 45 | highest: str = random.choice(list(dictionnary.keys())) 46 | secondHighest: str = random.choice(list(dictionnary.keys())) 47 | for str in dictionnary: 48 | if (dictionnary[str] > dictionnary[highest]): 49 | secondHighest = highest 50 | highest = str 51 | elif (dictionnary[str] > dictionnary[secondHighest]): 52 | secondHighest = str 53 | return (highest, secondHighest) 54 | 55 | # Get all possibilities of crossing over two strings 56 | # You can upgrade this function to more possibilities 57 | def getAllPossibilitiesOfCrossingOverTwoStrings(str1: str, str2: str) -> VectorStr: 58 | possibilities: VectorStr = [] 59 | for i in range(len(str1)): 60 | possibilities.append(str1[:i] + str2[i:]) 61 | return possibilities 62 | 63 | # Create a string with random characters with a length of len 64 | def createStringWithRandomChars(len: int) -> str: 65 | string: str = "" 66 | for i in range(len): 67 | string += chr(random.randint(97, 122)) 68 | return string 69 | 70 | # Initial population 71 | # Generate a population with a size of arrLength 72 | def initPopulation(arrLength: int) -> VectorStr: 73 | arr: VectorStr = [] 74 | 75 | for i in range(arrLength): 76 | arr.append(createStringWithRandomChars(len(goal))) 77 | return arr 78 | 79 | # Calc the score of the string compared to the goal 80 | # You can upgrade this fitness function to get a better result 81 | def fitnessFunction(str: str) -> int: 82 | res: str = goal 83 | score: int = 0 84 | i: int = 0 85 | j: int = 0 86 | while i < len(res): 87 | j = 0 88 | while j < len(str): 89 | if (res[i] == str[j]): 90 | arr = list(str) 91 | arr[j] = '~' 92 | str = "".join(arr) 93 | 94 | arr = list(res) 95 | arr[i] = '-' 96 | res = "".join(arr) 97 | 98 | score += 1 99 | j += 1 100 | i += 1 101 | return score 102 | 103 | # Calculate fitness for each string 104 | def createDictionnaryWithFitness(arrayStr: VectorStr) -> dict: 105 | dictionnary: dict = {} 106 | for str in arrayStr: 107 | dictionnary[str] = fitnessFunction(str) 108 | return dictionnary 109 | 110 | # Main function 111 | def GeneticAlgorithm() -> VectorStr: 112 | nbGeneration: int = 0 113 | population: VectorStr = initPopulation(30) 114 | print("Initial population: " + str(population)) 115 | dictionnary: dict = createDictionnaryWithFitness(population) 116 | while not checkSolutionInVectorStr(population): 117 | highest, secondHighest = getTwoStringWithHighestFitness(dictionnary) 118 | population = getAllPossibilitiesOfCrossingOverTwoStrings(highest, secondHighest) 119 | for i in range(len(population)): 120 | population[i] = mutationOfTenPercent(population[i]) 121 | dictionnary = createDictionnaryWithFitness(population) 122 | nbGeneration += 1 123 | print("Population :", population) 124 | print("Solution found in " + str(nbGeneration) + " generations") 125 | return population 126 | 127 | # Check if string has only alphabetic characters 128 | def hasOnlyAlphabeticCharactersInLowerCase(str: str) -> bool: 129 | return str.isalpha() and str.islower() 130 | 131 | if __name__ == "__main__": 132 | if (len(sys.argv) == 2): 133 | if (hasOnlyAlphabeticCharactersInLowerCase(sys.argv[1])): 134 | goal = sys.argv[1] 135 | print("The goal : " + str(goal)) 136 | GeneticAlgorithm() 137 | exit(0) 138 | else: 139 | print("Please enter a string composed only with characters in lower case.") 140 | exit(84) 141 | else: 142 | print("Please enter the goal as the first argument") 143 | exit(84) 144 | --------------------------------------------------------------------------------