Fix parent selection

This commit is contained in:
coolneng 2021-06-20 04:54:58 +02:00
parent 150457cc8e
commit b4a299cbf7
Signed by: coolneng
GPG Key ID: 9893DA236405AF57
1 changed files with 63 additions and 21 deletions

View File

@ -51,7 +51,7 @@ def evaluate_individual(individual, data):
def select_distinct_genes(matching_genes, parents, m): def select_distinct_genes(matching_genes, parents, m):
first_parent = parents[0].query("point not in @matching_genes") first_parent = parents[0].query("point not in @matching_genes")
second_parent = parents[1].query("point not in @matching_genes") second_parent = parents[1].query("point not in @matching_genes")
cutoff = randint(len(first_parent.point.values)) cutoff = randint(m - len(matching_genes))
first_parent_genes = first_parent.point.values[cutoff:] first_parent_genes = first_parent.point.values[cutoff:]
second_parent_genes = second_parent.point.values[:cutoff] second_parent_genes = second_parent.point.values[:cutoff]
return first_parent_genes, second_parent_genes return first_parent_genes, second_parent_genes
@ -65,18 +65,28 @@ def select_random_genes(matching_genes, parents, m):
return genes return genes
def select_random_parent(parents):
random_index = randint(len(parents))
random_parent = parents[random_index]
if random_parent.point.empty:
opposite_index = 1 - random_index
random_parent = parents[opposite_index]
return random_parent
def repair_offspring(offspring, parents, m): def repair_offspring(offspring, parents, m):
while len(offspring) != m: while len(offspring) != m:
if len(offspring) > m: if len(offspring) > m:
best_index = offspring["distance"].idxmax() best_index = offspring["distance"].idxmax()
offspring.drop(index=best_index, inplace=True) offspring.drop(index=best_index, inplace=True)
elif len(offspring) < m: elif len(offspring) < m:
random_parent = parents[randint(len(parents))] # NOTE Refactor into its own function
while True: while True:
random_parent = select_random_parent(parents)
best_index = random_parent["distance"].idxmax() best_index = random_parent["distance"].idxmax()
best_point = random_parent["point"].loc[best_index] best_point = random_parent["point"].loc[best_index]
random_parent.drop(index=best_index, inplace=True) random_parent.drop(index=best_index, inplace=True)
if not any(offspring["point"].isin([best_point])): if best_point not in offspring.point.values:
break break
offspring = offspring.append( offspring = offspring.append(
{"point": best_point, "distance": 0, "fitness": 0}, ignore_index=True {"point": best_point, "distance": 0, "fitness": 0}, ignore_index=True
@ -119,7 +129,7 @@ def position_crossover(parents, m):
def crossover(mode, parents, m): def crossover(mode, parents, m):
split_parents = [parents[i : i + 2] for i in range(0, len(parents), 2)] split_parents = zip(*[iter(parents)] * 2)
if mode == "uniform": if mode == "uniform":
crossover_func = partial(uniform_crossover, m=m) crossover_func = partial(uniform_crossover, m=m)
else: else:
@ -140,25 +150,36 @@ def select_new_gene(individual, n):
return new_gene return new_gene
def mutate(population, n, probability=0.001): def mutate(offspring, data, probability=0.001):
expected_mutations = len(population) * n * probability expected_mutations = len(offspring) * n * probability
individuals = [] individuals = []
genes = [] genes = []
for _ in range(ceil(expected_mutations)): for _ in range(ceil(expected_mutations)):
individuals.append(randint(n)) individuals.append(randint(len(offspring)))
current_individual = individuals[-1] current_individual = individuals[-1]
genes.append(population[current_individual].sample().index) genes.append(offspring[current_individual].sample().index)
for ind, gen in zip(individuals, genes): for ind, gen in zip(individuals, genes):
individual = population[ind] individual = offspring[ind]
individual["point"].iloc[gen] = select_new_gene(individual, n) individual["point"].iloc[gen] = select_new_gene(individual, n)
individual["distance"].iloc[gen] = 0 individual["distance"].iloc[gen] = compute_distance(
return population element=individual["point"].iloc[gen].values[0],
individual=individual,
data=data,
)
return offspring
def tournament_selection(m, population): def get_individual_index(population, element):
individuals = [population[randint(m)] for _ in range(2)] for index in range(len(population)):
best_index = population.index(max(population, key=lambda x: all(x.fitness))) if population[index].fitness.values[0] == element.fitness.values[0]:
return individuals[best_index] return index
def tournament_selection(population):
individuals = [population[randint(len(population))] for _ in range(2)]
best_element = max(individuals, key=lambda x: x.fitness.values[0])
population_index = get_individual_index(population, best_element)
return best_element, population_index
def generational_replacement(previous_population, current_population): def generational_replacement(previous_population, current_population):
@ -209,20 +230,41 @@ def evaluate_population(population, data, cores=4):
return evaluated_population return evaluated_population
def select_new_population(population, n, m, mode): def select_parents(population, n, mode):
select_population = population
parents = []
if mode == "generational": if mode == "generational":
parents = [tournament_selection(m, population) for _ in range(n)] for _ in range(n):
element, index = tournament_selection(population=select_population)
parents.append(element)
select_population.pop(index)
else: else:
parents = [tournament_selection(m, population) for _ in range(2)] for _ in range(2):
element, index = tournament_selection(population=select_population)
parents.append(element)
select_population.pop(index)
return parents return parents
def genetic_algorithm(n, m, data, mode, max_iterations=100000): def genetic_algorithm(n, m, data, select_mode, crossover_mode, max_iterations=100000):
population = [generate_individual(n, m, data) for _ in range(n)] population = [generate_individual(n, m, data) for _ in range(n)]
population = evaluate_population(population, data) population = evaluate_population(population, data)
for _ in range(max_iterations): for _ in range(max_iterations):
parents = select_new_population(population, n, m, mode) parents = select_parents(population, n, select_mode)
offspring = crossover(crossover_mode, parents, m)
offspring = mutate(offspring, data)
population = replace_population(population, offspring, select_mode)
population = evaluate_population(population, data)
best_solution, _ = get_best_elements(population)
return best_solution
n, m, data = parse_file("data/GKD-c_11_n500_m50.txt") n, m, data = parse_file("data/GKD-c_11_n500_m50.txt")
genetic_algorithm(n=10, m=5, data=data, mode="generational", max_iterations=1) genetic_algorithm(
n=10,
m=4,
data=data,
select_mode="generational",
crossover_mode="uniform",
max_iterations=1,
)