2022-06-07 01:07:49 +02:00
import itertools
import random
from data . Order import Order
from data . enum . GeneticMutationType import GeneticMutationType
from data . enum . Priority import Priority
class GeneticOrder :
2022-06-07 23:15:04 +02:00
mutation_chance = 10
reverse_chance = 60
cross_chance = 5
best_fit_special = 50
best_fit_super_special = 20
population_size = 200
2022-06-08 14:57:37 +02:00
number_of_populations = 10000
2022-06-07 23:15:04 +02:00
2022-06-08 14:57:37 +02:00
punish_low = 500
punish_med = 300
punish_sum = 50
2022-06-07 01:07:49 +02:00
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 )
2022-06-07 23:15:04 +02:00
if x < self . mutation_chance :
2022-06-07 01:07:49 +02:00
return GeneticMutationType . MUTATION
2022-06-07 23:15:04 +02:00
if x > self . mutation_chance + self . cross_chance :
2022-06-07 01:07:49 +02:00
return GeneticMutationType . REVERSE
return GeneticMutationType . CROSS
def mutation ( self , population : [ int ] ) - > [ int ] :
2022-06-08 14:57:37 +02:00
x = random . randint ( 0 , len ( population ) - 1 )
y = random . randint ( 0 , len ( population ) - 1 )
2022-06-07 01:07:49 +02:00
while x == y :
2022-06-08 14:57:37 +02:00
y = random . randint ( 0 , len ( population ) - 1 )
2022-06-07 01:07:49 +02:00
result = population
pom = population [ x ]
result [ x ] = population [ y ]
result [ y ] = pom
2022-06-08 14:57:37 +02:00
if ( result [ x ] == result [ y ] ) :
2022-06-07 01:07:49 +02:00
print ( " PIZDA I CHUJ " )
return result
def cross ( self , population : [ int ] ) - > [ int ] :
2022-06-08 14:57:37 +02:00
x = random . randint ( 1 , len ( population ) - 1 )
2022-06-07 01:07:49 +02:00
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 ) )
2022-06-08 14:57:37 +02:00
y = random . randint ( 0 , len ( population ) - 1 )
2022-06-07 23:15:04 +02:00
while y - x > 2 or x > = y :
2022-06-07 01:07:49 +02:00
x = random . randint ( 0 , len ( population ) )
2022-06-07 23:15:04 +02:00
y = random . randint ( 0 , len ( population ) - 1 )
2022-06-07 01:07:49 +02:00
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]
2022-06-08 14:57:37 +02:00
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
2022-06-07 23:15:04 +02:00
def sum_wrong ( self , member : [ int ] ) - > int :
last_high = 0
last_med = 0
2022-06-08 14:57:37 +02:00
last_prio = Priority . HIGH
last_sum = 0
2022-06-07 23:15:04 +02:00
counter = 0
for i in range ( len ( member ) ) :
o : Order = self . orders [ member [ i ] ]
2022-06-08 14:57:37 +02:00
if o . priority == Priority . HIGH :
2022-06-07 23:15:04 +02:00
last_high = i
elif o . priority == Priority . MEDIUM :
last_med = i
2022-06-08 14:57:37 +02:00
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
2022-06-07 23:15:04 +02:00
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
2022-06-07 01:07:49 +02:00
def evaluate ( self , member : [ int ] ) - > int :
2022-06-07 23:15:04 +02:00
# 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)
2022-06-07 01:07:49 +02:00
2022-06-07 23:15:04 +02:00
# return result
2022-06-07 01:07:49 +02:00
2022-06-07 23:15:04 +02:00
return self . sum_wrong ( member )
2022-06-07 01:07:49 +02:00
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 = [ ]
2022-06-07 23:15:04 +02:00
for i in range ( len ( population ) - self . best_fit_special - self . best_fit_super_special ) :
result . append ( population [ i ] )
2022-06-07 01:07:49 +02:00
2022-06-07 23:15:04 +02:00
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 ] )
2022-06-07 01:07:49 +02:00
return result
def get_orders_sorted ( self , orders : [ Order ] ) - > [ Order ] :
self . orders = orders
population : [ [ int ] ] = self . generate_first_population ( self . population_size )
2022-06-07 23:15:04 +02:00
# print(population)
2022-06-07 01:07:49 +02:00
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 ] ] )
2022-06-08 14:57:37 +02:00
return result