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):
|
||||
first_parent = parents[0].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:]
|
||||
second_parent_genes = second_parent.point.values[:cutoff]
|
||||
return first_parent_genes, second_parent_genes
|
||||
|
@ -65,18 +65,28 @@ def select_random_genes(matching_genes, parents, m):
|
|||
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):
|
||||
while len(offspring) != m:
|
||||
if len(offspring) > m:
|
||||
best_index = offspring["distance"].idxmax()
|
||||
offspring.drop(index=best_index, inplace=True)
|
||||
elif len(offspring) < m:
|
||||
random_parent = parents[randint(len(parents))]
|
||||
# NOTE Refactor into its own function
|
||||
while True:
|
||||
random_parent = select_random_parent(parents)
|
||||
best_index = random_parent["distance"].idxmax()
|
||||
best_point = random_parent["point"].loc[best_index]
|
||||
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
|
||||
offspring = offspring.append(
|
||||
{"point": best_point, "distance": 0, "fitness": 0}, ignore_index=True
|
||||
|
@ -119,7 +129,7 @@ def position_crossover(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":
|
||||
crossover_func = partial(uniform_crossover, m=m)
|
||||
else:
|
||||
|
@ -140,25 +150,36 @@ def select_new_gene(individual, n):
|
|||
return new_gene
|
||||
|
||||
|
||||
def mutate(population, n, probability=0.001):
|
||||
expected_mutations = len(population) * n * probability
|
||||
def mutate(offspring, data, probability=0.001):
|
||||
expected_mutations = len(offspring) * n * probability
|
||||
individuals = []
|
||||
genes = []
|
||||
for _ in range(ceil(expected_mutations)):
|
||||
individuals.append(randint(n))
|
||||
individuals.append(randint(len(offspring)))
|
||||
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):
|
||||
individual = population[ind]
|
||||
individual = offspring[ind]
|
||||
individual["point"].iloc[gen] = select_new_gene(individual, n)
|
||||
individual["distance"].iloc[gen] = 0
|
||||
return population
|
||||
individual["distance"].iloc[gen] = compute_distance(
|
||||
element=individual["point"].iloc[gen].values[0],
|
||||
individual=individual,
|
||||
data=data,
|
||||
)
|
||||
return offspring
|
||||
|
||||
|
||||
def tournament_selection(m, population):
|
||||
individuals = [population[randint(m)] for _ in range(2)]
|
||||
best_index = population.index(max(population, key=lambda x: all(x.fitness)))
|
||||
return individuals[best_index]
|
||||
def get_individual_index(population, element):
|
||||
for index in range(len(population)):
|
||||
if population[index].fitness.values[0] == element.fitness.values[0]:
|
||||
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):
|
||||
|
@ -209,20 +230,41 @@ def evaluate_population(population, data, cores=4):
|
|||
return evaluated_population
|
||||
|
||||
|
||||
def select_new_population(population, n, m, mode):
|
||||
def select_parents(population, n, mode):
|
||||
select_population = population
|
||||
parents = []
|
||||
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:
|
||||
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
|
||||
|
||||
|
||||
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 = evaluate_population(population, data)
|
||||
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")
|
||||
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