import itertools import random from data.Order import Order from data.enum.GeneticMutationType import GeneticMutationType from data.enum.Priority import Priority class GeneticOrder: mutation_chance = 10 reverse_chance = 60 cross_chance = 5 best_fit_special = 50 best_fit_super_special = 20 population_size = 200 number_of_populations = 1000 punish_low = 5 punish_med = 3 def __init__(self, orders: [Order]) -> None: self.orders = orders def get_mutation_type(self) -> GeneticMutationType: x = random.randint(0, self.mutation_chance + self.cross_chance + self.reverse_chance) if x < self.mutation_chance: return GeneticMutationType.MUTATION if x > self.mutation_chance + self.cross_chance: return GeneticMutationType.REVERSE return GeneticMutationType.CROSS def mutation(self, population: [int]) -> [int]: x = random.randint(0, len(population)-1) y = random.randint(0, len(population)-1) while x == y: y = random.randint(0, len(population)-1) result = population pom = population[x] result[x] = population[y] result[y] = pom if(result[x] == result[y]): print("PIZDA I CHUJ") return result def cross(self, population: [int]) -> [int]: x = random.randint(1, len(population)-1) result = [] for i in range(len(population)): result.append(population[(i + x) % len(population)]) return result def reverse(self, population: [int]) -> [int]: x = random.randint(0, len(population)) y = random.randint(0, len(population)-1) while y - x > 2 or x >= y: x = random.randint(0, len(population)) y = random.randint(0, len(population) - 1) result = [] # print("X: ", x, " y: ", y) for i in range(len(population)): if x <= i <= y: new_i = i - x # print("len:", len(population), " new_i: ", new_i) result.append(population[y - new_i]) else: result.append(population[i]) return result def generate_first_population(self, k: int) -> [[int]]: result = [] s = range(len(self.orders)) p = itertools.permutations(s) while len(result) < k: n = p.__next__() if n not in result: result.append(n) return [list(x) for x in result] # result = itertools.permutations(range(len(self.orders))) # # return [list(x) for x in result] def sum_wrong(self, member: [int]) -> int: last_high = 0 last_med = 0 counter = 0 for i in range(len(member)): o: Order = self.orders[member[i]] if o.priority == Priority.HIGH : last_high = i elif o.priority == Priority.MEDIUM: last_med = i for i in range(last_high): o: Order = self.orders[member[i]] if o.priority == Priority.MEDIUM: counter += self.punish_med elif o.priority == Priority.LOW: counter += self.punish_low for i in range(last_med): o: Order = self.orders[member[i]] if o.priority == Priority.LOW: counter += self.punish_low return counter def evaluate(self, member: [int]) -> int: # result = 0 # for i in range(len(self.orders) - 1): # x: Order = self.orders[member[i]] # y: Order = self.orders[member[i + 1]] # # if ((x.priority == Priority.MEDIUM or x.priority == Priority.LOW) and y.priority == Priority.HIGH) or (x.priority == Priority.LOW and y.priority == Priority.MEDIUM): # result += 30 # # if x.sum / x.time < y.sum / y.time: # result += int(y.sum / y.time) # return result return self.sum_wrong(member) def mutate_population(self, order_population: [[int]]) -> [[int]]: result = [] for i in range(len(order_population)): member: [int] = order_population[i] operation: GeneticMutationType = self.get_mutation_type() if operation == GeneticMutationType.MUTATION: member = self.mutation(member) elif operation == GeneticMutationType.REVERSE: member = self.reverse(member) else: member = self.cross(member) result.append(member) return result def get_next_population(self, population: [[int]]) -> [[int]]: result = [] for i in range(len(population) - self.best_fit_special - self.best_fit_super_special): result.append(population[i]) for i in range(self.best_fit_special): x = random.randint(0, self.best_fit_special) result.append(population[x]) for i in range(self.best_fit_super_special): x = random.randint(0, self.best_fit_super_special) result.append(population[x]) return result def get_orders_sorted(self, orders: [Order]) -> [Order]: self.orders = orders population: [[int]] = self.generate_first_population(self.population_size) # print(population) population.sort(key=self.evaluate) best_fit: [int] = population[0] for i in range(self.number_of_populations): # print("population: ", i) population = self.mutate_population(population) population.sort(key=self.evaluate) if self.evaluate(best_fit) > self.evaluate(population[0]): best_fit = population[0] # population = self.get_next_population(population).sort(key=self.evaluate) if self.evaluate(best_fit) < self.evaluate(population[0]): population[0] = best_fit best: [int] = population[0] result: [Order] = [] for i in range(len(best)): result.append(self.orders[best[i]]) return result