diff --git a/src/AI/GaTravelingForHerbs/GeneticAlgorithm.py b/src/AI/GaTravelingForHerbs/GeneticAlgorithm.py index 77a1416..31bab59 100644 --- a/src/AI/GaTravelingForHerbs/GeneticAlgorithm.py +++ b/src/AI/GaTravelingForHerbs/GeneticAlgorithm.py @@ -1,4 +1,38 @@ from random import random, choice class GeneticAlgorithm: - pass \ No newline at end of file + def __init__(self, firstPopulation, mutationProbability): + self.firstPopulation = firstPopulation + self.mutationProbability = mutationProbability + + def selectionModel(self, generation): + max_selected = int(len(generation) / 10) + sorted_by_assess = sorted(generation, key=lambda x: x.fitness) + return sorted_by_assess[:max_selected] + + def stopCondition(self, i): + return i == 100 + + def run(self): + population = self.firstPopulation + population.sort(key=lambda x: x.fitness) + populationLen = len(population) + i = 0 + while True: + selected = self.selectionModel(population) + newPopulation = selected.copy() + while len(newPopulation) != populationLen: + child = choice(population).crossover(choice(population)) + if random() <= self.mutationProbability: + child.mutation() + newPopulation.append(child) + + population = newPopulation + theBestMatch = min(population, key=lambda x: x.fitness) + print("Generation: {} S: {} fitness: {}".format(i, theBestMatch, theBestMatch.fitness)) + + i += 1 + if self.stopCondition(i): + return theBestMatch + + diff --git a/src/AI/GaTravelingForHerbs/Traveling.py b/src/AI/GaTravelingForHerbs/Traveling.py index 33332a4..de3fea8 100644 --- a/src/AI/GaTravelingForHerbs/Traveling.py +++ b/src/AI/GaTravelingForHerbs/Traveling.py @@ -1,10 +1,51 @@ from random import randint, sample from math import sqrt +from src.AI.GaTravelingForHerbs.GeneticAlgorithm import GeneticAlgorithm + START_COORD = [(6, 2)] END_COORD = [(10, 7)] COORDS = [(12, 2), (16, 2), (17, 5), (14, 7), (17, 17), (13, 17), (5, 15), (2, 9), (8, 5), (11, 10)] + class Traveling: def __init__(self, coords): - self.coords = coords \ No newline at end of file + self.coords = coords + self.fitness = self.evaluate() + + def evaluate(self): + sum = 0 + for i, c in enumerate(self.coords): + if i + 1 > len(self.coords) - 1: + break + nextCoord = self.coords[i + 1] + # calculate distance + sum += sqrt((nextCoord[0] - c[0]) ** 2 + (nextCoord[1] - c[1]) ** 2) + return sum + + def crossover(self, element2: 'Element') -> 'Element': + childCoords = self.coords[1:int(len(self.coords) / 2)] + for coord in element2.coords: + if coord not in childCoords and coord not in END_COORD + START_COORD: + childCoords.append(coord) + + if len(childCoords) == len(element2.coords): + break + return Traveling(START_COORD + childCoords + END_COORD) + + def mutation(self): + first = randint(1, len(self.coords) - 2) + second = randint(1, len(self.coords) - 2) + self.coords[first], self.coords[second] = self.coords[second], self.coords[first] + self.fitness = self.evaluate() + + def __repr__(self): + return str(self.coords) + + +firstGeneration = [Traveling(START_COORD + sample(COORDS, len(COORDS)) + END_COORD) for _ in range(100)] +mutationProbability = float(0.1) + +ga = GeneticAlgorithm(firstGeneration, mutationProbability) +movementList = ga.run() +