Fix parent selection
This commit is contained in:
parent
150457cc8e
commit
b4a299cbf7
|
@ -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,
|
||||||
|
)
|
||||||
|
|
Loading…
Reference in New Issue