diff --git a/src/genetic_algorithm.py b/src/genetic_algorithm.py index 537a35d..45b1b41 100644 --- a/src/genetic_algorithm.py +++ b/src/genetic_algorithm.py @@ -1,10 +1,11 @@ -from numpy import sum, append, intersect1d, array_equal +from numpy import intersect1d, array_equal from numpy.random import randint, choice, shuffle from pandas import DataFrame from math import ceil from functools import partial from multiprocessing import Pool from copy import deepcopy +from itertools import combinations def get_row_distance(source, destination, data): @@ -35,22 +36,23 @@ def generate_individual(n, m, data): def evaluate_individual(individual, data): - fitness = [] - genotype = individual.point.values - distances = data.query(f"source in @genotype and destination in @genotype") - for item in genotype[:-1]: - element_df = distances.query(f"source == {item} or destination == {item}") - max_distance = element_df["distance"].astype(float).max() - fitness = append(arr=fitness, values=max_distance) - distances = distances.query(f"source != {item} and destination != {item}") - individual["fitness"] = sum(fitness) + fitness = 0 + comb = combinations(individual.index, r=2) + for index in list(comb): + elements = individual.loc[index, :] + fitness += get_row_distance( + source=elements["point"].head(n=1).values[0], + destination=elements["point"].tail(n=1).values[0], + data=data, + ) + individual["fitness"] = fitness return individual def select_distinct_genes(matching_genes, parents, m): first_parent = parents[0].query("point not in @matching_genes") second_parent = parents[1].query("point not in @matching_genes") - cutoff = randint(m - len(matching_genes)) + cutoff = randint(m - len(matching_genes) + 1) first_parent_genes = first_parent.point.values[cutoff:] second_parent_genes = second_parent.point.values[:cutoff] return first_parent_genes, second_parent_genes @@ -137,9 +139,8 @@ def group_parents(parents): first = parents[i] second = parents[i + 1] if array_equal(first.point.values, second.point.values): - tmp = second - second = parents[i - 2] - parents[i - 2] = tmp + random_index = randint(i + 1) + second, parents[random_index] = parents[random_index], second parent_pairs.append([first, second]) return parent_pairs diff --git a/src/main.py b/src/main.py index 6d9af05..887484b 100755 --- a/src/main.py +++ b/src/main.py @@ -1,9 +1,7 @@ from preprocessing import parse_file from genetic_algorithm import genetic_algorithm from memetic_algorithm import memetic_algorithm -from sys import argv from time import time -from itertools import combinations from argparse import ArgumentParser @@ -17,54 +15,24 @@ def execute_algorithm(args, n, m, data): crossover_mode=args.crossover, max_iterations=100, ) - else: - return memetic_algorithm( - n, - m, - data, - hybridation=args.hybridation, - max_iterations=100, - ) - - -def get_row_distance(source, destination, data): - row = data.query( - """(source == @source and destination == @destination) or \ - (source == @destination and destination == @source)""" + return memetic_algorithm( + n, + m, + data, + hybridation=args.hybridation, + max_iterations=100, ) - return row["distance"].values[0] -def get_fitness(solutions, data): - counter = 0 - comb = combinations(solutions.index, r=2) - for index in list(comb): - elements = solutions.loc[index, :] - counter += get_row_distance( - source=elements["point"].head(n=1).values[0], - destination=elements["point"].tail(n=1).values[0], - data=data, - ) - return counter - - -def show_results(solutions, fitness, time_delta): - duplicates = solutions.duplicated().any() - print(solutions) - print(f"Total distance: {fitness}") +def show_results(solution, time_delta): + duplicates = solution.duplicated().any() + print(solution) + print(f"Total distance: {solution.fitness.values[0]}") if not duplicates: print("No duplicates found") print(f"Execution time: {time_delta}") -def usage(argv): - print(f"Usage: python {argv[0]} <") - print("algorithm choices:") - print("genetic: genetic algorithm") - print("memetic: memetic algorithm") - exit(1) - - def parse_arguments(): parser = ArgumentParser() parser.add_argument("file", help="dataset of choice") @@ -83,8 +51,7 @@ def main(): start_time = time() solutions = execute_algorithm(args, n, m, data) end_time = time() - fitness = get_fitness(solutions, data) - show_results(solutions, fitness, time_delta=end_time - start_time) + show_results(solutions, time_delta=end_time - start_time) if __name__ == "__main__":