SI_InteligentnyWozekWidlowy/genetic_order/GeneticOrder.py

219 lines
6.5 KiB
Python

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 = 10000
punish_low = 500
punish_med = 300
punish_sum = 50
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 correct_sum(self, last_prio: Priority, last_sum: float, o: Order) -> bool:
if o.priority == last_prio:
return last_sum > o.sum / o.time
return True
def sum_wrong(self, member: [int]) -> int:
last_high = 0
last_med = 0
last_prio = Priority.HIGH
last_sum = 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
if not self.correct_sum(last_prio, last_sum, o):
counter += int(last_sum - (o.sum / o.time))
last_prio = o.priority
last_sum = o.sum / o.time
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