diff --git a/genetics b/genetics new file mode 100644 index 0000000..7c65a13 --- /dev/null +++ b/genetics @@ -0,0 +1,116 @@ +import numpy as np +import random + +# parametry +num_of_houses = 4 # ilość domków +routes_num = 10 # ilość ścieżek, które będziemy generować +#rate = 0.3 # do mutacji, by liczby były ładniejsze +houses_coordinates = [[x,y] for x,y in zip(np.random.randint(1,9,num_of_houses),np.random.randint(1,9,num_of_houses))] # generowanie losowych współrzędnych między 1, a 9 +names = np.array(['Dom A', 'Dom B', 'Dom C', 'Dom D', 'Dom E', 'Dom F', 'Dom G', 'Dom H']) # nazwy domów +houses_info = { x:y for x,y in zip(names,houses_coordinates)} # zawiera nazwę domu i jego współrzędne X, Y - słownik +print(houses_info) + +# dystans - to się wywali i użyje astara +def house_distance(a,b): + return ((a[0]-b[0])**2+(a[1]-b[1])**2)**0.5 + + +def generate_routes(names, routes_num): # tu się robią te zestawy domów - routes_num różnych opcji ułożenia trasy przez wszystkie domy + population_set = [] # tu zapisujemy trasy - losowe ułóżenia wszystkich domów na trasie śmieciarki - nasza populacja + for i in range(routes_num): + # losowo wygenerowane kolejności domów na trasie + single_route = names[np.random.choice(list(range(num_of_houses)), num_of_houses, replace=False)] + population_set.append(single_route) + return np.array(population_set) + + +def sum_up_for_route(names, houses_info): # liczymy odległości między kolejnymi miastami z listy i sumujemy + sum = 0 + for i in range(num_of_houses-1): + sum += house_distance(houses_info[names[i]], houses_info[names[i+1]]) # wywołana funkcja, która oblicza dystans - ma być astar + return sum + + +def sums_for_all_routes(population_set, houses_info): # zapisujemy na liście finalne sumy odległości(astara) dla każdej z opcji tras + list_of_sums = np.zeros(routes_num) + + for i in range(routes_num): + list_of_sums[i] = sum_up_for_route(population_set[i], houses_info) # wywołujemy dla każdej trasy na liście + + return list_of_sums + + +def selection(population_set, list_of_sums): # korzystamy z Roulette Wheel Selection tzn. im większy fitness tym większa szansa na zostanie wybranym + determinant = list_of_sums.sum() + probability = list_of_sums/determinant # nasza funkcja przynależności - dzielimy każdy dystans konkretnej ścieżki przez sumę wszystkich + + progenitor_a = np.random.choice(list(range(len(population_set))), len(population_set), p=probability, + replace=True) # randomowa lista złożona z liczb między 0, a routes_num - 1 + progenitor_b = np.random.choice(list(range(len(population_set))), len(population_set), p=probability, + replace=True) # gdzie p to prawdopodobieństwo każdego wejścia + + progenitor_a = population_set[progenitor_a] # zmieniamy kolejność ułożenia tras + progenitor_b = population_set[progenitor_b] # teraz nie zawierają liczb, tylko podlisty z trasami + + return np.array([progenitor_a, progenitor_b]) + + +def mating_of_progenitors(progenitor_a, progenitor_b): + child = progenitor_a[0:5] # bierzemy 5 domów z rodzica + + for house in progenitor_b: + if not house in child: # jeżeli jakiegoś domu z rodzica b nie ma w dziecku z a to łączymy + child = np.concatenate((child, [house])) + + return child + + +def population_mating(progenitor_list): + new_population_set = [] + for i in range(progenitor_list.shape[1]): + progenitor_a, progenitor_b = progenitor_list[0][i], progenitor_list[1][i] + child = mating_of_progenitors(progenitor_a, progenitor_b) + new_population_set.append(child) + + return new_population_set + + +def mutation_of_child(child): + for i in range(num_of_houses): # dla każdego elementu dajemy losową szansę zamiany int *rate + x = np.random.randint(0, num_of_houses) + y = np.random.randint(0, num_of_houses) + + child[x], child[y] = child[y], child[x] # zamiana miejscami + + return child + + +def mutate_population(new_population_set): + final_mutated_population = [] + for child in new_population_set: + final_mutated_population.append(mutation_of_child(child)) # dodajemy zmutowane dziecko do finalnej listy + return final_mutated_population + + +if __name__ == '__main__': + + population_set = generate_routes(names, routes_num) + list_of_sums = sums_for_all_routes(population_set, houses_info) + progenitor_list = selection(population_set, list_of_sums) + new_population_set = population_mating(progenitor_list) + final_mutated_population = mutate_population(new_population_set) + final_route = [-1, np.inf, np.array([])] # format listy + for i in range(20): + list_of_sums = sums_for_all_routes(final_mutated_population, houses_info) + # zapisujemy najlepsze rozwiązanie + if list_of_sums.min() < final_route[1]: + final_route[0] = i + final_route[1] = list_of_sums.min() + final_route[2] = np.array(final_mutated_population)[list_of_sums.min() == list_of_sums] + + progenitor_list = selection(population_set, list_of_sums) + new_population_set = population_mating(progenitor_list) + + final_mutated_population = mutate_population(new_population_set) + print(final_route) +