2020-05-08 23:23:12 +02:00
|
|
|
import random
|
2020-05-10 16:20:04 +02:00
|
|
|
import math
|
2020-05-08 23:23:12 +02:00
|
|
|
### prawdopodobieństwo mutacji
|
2020-05-11 11:53:55 +02:00
|
|
|
mutation_prob = 0.03
|
2020-05-10 16:20:04 +02:00
|
|
|
### ilość osobników w pokoleniu, powinna być parzysta
|
2020-06-15 15:03:47 +02:00
|
|
|
# generation_size = 40
|
2020-05-08 23:23:12 +02:00
|
|
|
### liczba pokoleń
|
2020-06-15 15:03:47 +02:00
|
|
|
# number_of_generations = 30
|
2020-05-08 23:23:12 +02:00
|
|
|
### jak bardzo promowane są osobniki wykorzystujące całą pojemność regału
|
2020-06-15 14:10:33 +02:00
|
|
|
amount_of_promotion = 5
|
2020-05-08 23:23:12 +02:00
|
|
|
|
|
|
|
|
2020-06-15 15:03:47 +02:00
|
|
|
def first_gen(number_of_packages, number_of_racks, generation_size):
|
2020-05-08 23:23:12 +02:00
|
|
|
first_generation = []
|
|
|
|
for individual in range(generation_size):
|
|
|
|
individual = []
|
|
|
|
for pack in range(number_of_packages):
|
|
|
|
r = random.randint(0,number_of_racks-1)
|
|
|
|
individual.append(r)
|
|
|
|
first_generation.append(individual)
|
|
|
|
return first_generation
|
|
|
|
|
2020-06-15 15:03:47 +02:00
|
|
|
# def evaluation(individual, packages, racks, number_of_packages, number_of_racks, tree_predictor):
|
|
|
|
# # im większy fitness tym lepszy osobnik
|
|
|
|
# # print("regały: ",racks)
|
|
|
|
# rest_of_capacity = [rack.capacity for rack in racks]
|
|
|
|
# # print("początkowa pojemność: ",rest_of_capacity)
|
|
|
|
# for i in range(number_of_packages):
|
|
|
|
# can_place = tree_predictor.check_if_can_place(packages[i], racks[i])
|
|
|
|
# if not can_place:
|
|
|
|
# rest_of_capacity[individual[i]] -= packages[i].size * 5
|
|
|
|
# else:
|
|
|
|
# rest_of_capacity[individual[i]] -= packages[i].size
|
|
|
|
# # print("pozostała pojemność: ",rest_of_capacity)
|
|
|
|
# # pdb.set_trace()
|
|
|
|
# fitness = 0
|
|
|
|
# for i in range(number_of_racks):
|
|
|
|
# # jak regał jest przepełniony, zmniejsza fitness osobnika
|
|
|
|
# if rest_of_capacity[i] < 0:
|
|
|
|
# fitness += rest_of_capacity[i]
|
|
|
|
# # delikane promowanie osobników wykorzystujących regały w pełni
|
|
|
|
# elif rest_of_capacity[i] == 0:
|
|
|
|
# fitness += 2
|
|
|
|
# else:
|
|
|
|
# fitness += 1
|
|
|
|
# return fitness
|
|
|
|
|
|
|
|
|
2020-06-15 11:55:24 +02:00
|
|
|
def evaluation(individual, packages, racks, number_of_packages, number_of_racks, tree_predictor):
|
2020-05-08 23:23:12 +02:00
|
|
|
# im większy fitness tym lepszy osobnik
|
|
|
|
# print("regały: ",racks)
|
2020-06-15 14:10:33 +02:00
|
|
|
rest_of_capacity = [rack.capacity for rack in racks]
|
2020-05-08 23:23:12 +02:00
|
|
|
# print("początkowa pojemność: ",rest_of_capacity)
|
2020-06-15 15:03:47 +02:00
|
|
|
bad_placed = 0
|
2020-05-08 23:23:12 +02:00
|
|
|
for i in range(number_of_packages):
|
2020-06-15 15:03:47 +02:00
|
|
|
rest_of_capacity[individual[i]] -= packages[i].size
|
2020-06-15 14:10:33 +02:00
|
|
|
can_place = tree_predictor.check_if_can_place(packages[i], racks[i])
|
|
|
|
if not can_place:
|
2020-06-15 15:03:47 +02:00
|
|
|
bad_placed +=1
|
2020-05-08 23:23:12 +02:00
|
|
|
# print("pozostała pojemność: ",rest_of_capacity)
|
2020-06-15 14:10:33 +02:00
|
|
|
# pdb.set_trace()
|
2020-05-08 23:23:12 +02:00
|
|
|
fitness = 0
|
|
|
|
for i in range(number_of_racks):
|
|
|
|
# jak regał jest przepełniony, zmniejsza fitness osobnika
|
|
|
|
if rest_of_capacity[i] < 0:
|
|
|
|
fitness += rest_of_capacity[i]
|
|
|
|
# delikane promowanie osobników wykorzystujących regały w pełni
|
|
|
|
elif rest_of_capacity[i] == 0:
|
2020-06-15 15:03:47 +02:00
|
|
|
fitness += amount_of_promotion
|
|
|
|
fitness -= 5*bad_placed
|
2020-05-08 23:23:12 +02:00
|
|
|
return fitness
|
|
|
|
|
2020-06-15 15:03:47 +02:00
|
|
|
def roulette(generation, packages, generation_size ,racks, number_of_packages, number_of_racks, tree_predictor):
|
2020-05-08 23:23:12 +02:00
|
|
|
# print('pokolenie: ', generation)
|
|
|
|
evaluations = []
|
|
|
|
for i in range(generation_size):
|
2020-06-15 11:55:24 +02:00
|
|
|
individual_fitness = evaluation(generation[i], packages, racks, number_of_packages, number_of_racks, tree_predictor)
|
2020-05-08 23:23:12 +02:00
|
|
|
evaluations.append(individual_fitness)
|
2020-05-10 16:20:04 +02:00
|
|
|
# print("tablica dopasowań: ", evaluations)
|
|
|
|
maximum = min(evaluations)
|
2020-05-08 23:23:12 +02:00
|
|
|
# dodaję tą 1 żeby nie wywalać najgorszego osobnika
|
2020-05-10 16:20:04 +02:00
|
|
|
normalized = [x+(-1*maximum)+1 for x in evaluations]
|
2020-05-08 23:23:12 +02:00
|
|
|
# print(normalized)
|
|
|
|
sum_of_normalized = sum(normalized)
|
|
|
|
roulette_tab = [x/sum_of_normalized for x in normalized]
|
|
|
|
# print(roulette_tab)
|
|
|
|
for i in range(1,generation_size-1):
|
|
|
|
roulette_tab[i] += roulette_tab[i-1]
|
|
|
|
# wpisuję 1 ręcznie, bo czasem liczby nie sumowały się idealnie do 1
|
|
|
|
#(niedokładność komputera)
|
|
|
|
roulette_tab[generation_size-1] = 1
|
|
|
|
# print("ruletka: ", roulette_tab)
|
|
|
|
survivors = []
|
|
|
|
for individual in range(generation_size):
|
|
|
|
random_number = random.random()
|
|
|
|
interval_number = 0
|
|
|
|
while random_number > roulette_tab[interval_number]:
|
|
|
|
interval_number += 1
|
|
|
|
survivors.append(generation[interval_number])
|
|
|
|
# print('przetrwali: ',survivors)
|
|
|
|
return survivors
|
|
|
|
|
2020-05-11 14:54:33 +02:00
|
|
|
def crossover(individual1, individual2, number_of_packages):
|
2020-05-08 23:23:12 +02:00
|
|
|
cut = random.randint(1,number_of_packages-1)
|
|
|
|
new1 = individual1[:cut]
|
|
|
|
new2 = individual2[:cut]
|
|
|
|
new1 = new1 + individual2[cut:]
|
|
|
|
new2 = new2 + individual1[cut:]
|
|
|
|
# print(individual1)
|
|
|
|
# print(individual2)
|
|
|
|
# print(new1)
|
|
|
|
# print(new2)
|
|
|
|
# print(cut)
|
|
|
|
return new1, new2
|
|
|
|
|
2020-05-11 14:54:33 +02:00
|
|
|
def mutation(individual, number_of_packages, number_of_racks):
|
2020-05-10 16:20:04 +02:00
|
|
|
# print(individual)
|
2020-05-08 23:23:12 +02:00
|
|
|
locus = random.randint(0,number_of_packages-1)
|
|
|
|
individual[locus] = random.randint(0,number_of_racks-1)
|
|
|
|
return individual
|
|
|
|
|
2020-05-10 16:20:04 +02:00
|
|
|
|
2020-06-15 11:55:24 +02:00
|
|
|
def gen_alg(packages, racks, number_of_generations, generation_size, mutation_prob, amount_of_promotion, tree_predictor):
|
2020-05-11 14:54:33 +02:00
|
|
|
number_of_packages = len(packages)
|
|
|
|
number_of_racks = len(racks)
|
|
|
|
|
2020-05-11 11:53:55 +02:00
|
|
|
### WŁAŚCIWY ALGORYTM
|
2020-06-15 15:03:47 +02:00
|
|
|
generation = first_gen(number_of_packages, number_of_racks, generation_size)
|
2020-05-11 11:53:55 +02:00
|
|
|
global_maximum = -math.inf
|
2020-05-10 16:20:04 +02:00
|
|
|
|
2020-05-11 11:53:55 +02:00
|
|
|
# pętla znajdująca najlepszy fitness w pierwszym pokoleniu
|
|
|
|
for i in range(generation_size):
|
2020-06-15 11:55:24 +02:00
|
|
|
evaluation_of_individual = evaluation(generation[i], packages, racks, number_of_packages, number_of_racks, tree_predictor)
|
2020-05-11 11:53:55 +02:00
|
|
|
if evaluation_of_individual > global_maximum:
|
|
|
|
global_maximum = evaluation_of_individual
|
|
|
|
best_individual = generation[i].copy()
|
2020-05-10 16:20:04 +02:00
|
|
|
|
2020-05-11 11:53:55 +02:00
|
|
|
#właściwa pętla programu
|
|
|
|
for generation_index in range(number_of_generations):
|
2020-06-15 11:55:24 +02:00
|
|
|
# print('pokolenie numer: ', generation_index)
|
2020-05-11 11:53:55 +02:00
|
|
|
# print(generation)
|
2020-05-10 16:20:04 +02:00
|
|
|
|
2020-05-11 11:53:55 +02:00
|
|
|
### RULETKA
|
2020-06-15 15:03:47 +02:00
|
|
|
survivors = roulette(generation, packages, generation_size, racks, number_of_packages, number_of_racks, tree_predictor)
|
2020-05-11 11:53:55 +02:00
|
|
|
# print('przetrwali: ',survivors)
|
2020-05-10 16:20:04 +02:00
|
|
|
|
2020-05-11 11:53:55 +02:00
|
|
|
### KRZYŻOWANIE
|
|
|
|
descendants = []
|
|
|
|
for individual in range(0,generation_size,2):
|
2020-05-11 14:54:33 +02:00
|
|
|
pair = crossover(survivors[individual],survivors[individual+1], number_of_packages)
|
2020-05-11 11:53:55 +02:00
|
|
|
for each in pair:
|
|
|
|
descendants.append(each)
|
|
|
|
# print('potomkowie: ', descendants)
|
2020-05-10 16:20:04 +02:00
|
|
|
|
2020-05-11 11:53:55 +02:00
|
|
|
### MUTACJA
|
|
|
|
for individual in range(generation_size):
|
|
|
|
if random.random() <= mutation_prob:
|
2020-05-11 14:54:33 +02:00
|
|
|
mutation(descendants[individual], number_of_packages, number_of_racks)
|
2020-05-11 11:53:55 +02:00
|
|
|
# print('potomkowie po mutacji: ', descendants)
|
|
|
|
|
|
|
|
### NAJLEPSZE DOPASOWANIE
|
|
|
|
local_maximum = -math.inf
|
|
|
|
for each in range(generation_size):
|
2020-06-15 11:55:24 +02:00
|
|
|
specific_fitness = evaluation(descendants[each], packages, racks, number_of_packages, number_of_racks, tree_predictor)
|
2020-05-11 11:53:55 +02:00
|
|
|
if specific_fitness > local_maximum:
|
|
|
|
local_maximum = specific_fitness
|
2020-05-11 14:54:33 +02:00
|
|
|
generation_best_individual = descendants[each].copy()
|
|
|
|
print('maksimum w pokoleniu: ',local_maximum)
|
2020-05-11 11:53:55 +02:00
|
|
|
if local_maximum > global_maximum:
|
|
|
|
global_maximum = local_maximum
|
2020-05-11 14:54:33 +02:00
|
|
|
best_individual = generation_best_individual.copy()
|
2020-05-11 11:53:55 +02:00
|
|
|
generation = descendants
|
2020-05-11 14:54:33 +02:00
|
|
|
print('maksimum globalne: ', global_maximum)
|
2020-06-15 11:55:24 +02:00
|
|
|
# print("jeśli maksimum globalne wynosi 0, każda paczka ma swój regał")
|
2020-05-11 14:54:33 +02:00
|
|
|
print("najlepsze dopasowanie: ", best_individual)
|