I'm trying to implement a genetic algorithm and I'm running into a very weird issue.
I have the following loop for running the genetic algorithm:
while True:
# Calc population fitness
population_fitness, best_individual = self.fitness(pop)
print(best_individual)
print(max(population_fitness))
# Select 50% of population
selected_population = self.selection(pop, population_fitness)
# Perform crossover
new_pop = []
for i in range(pop_size - 1):
parent1 = selected_population[randrange(0, len(selected_population))]
parent2 = selected_population[randrange(0, len(selected_population))]
child = self.crossover(parent1, parent2)
# Perform mutation
if randrange(0, 100) > 92:
child = self.mutation(child)
new_pop.append(child)
new_pop.append(best_individual)
pop = new_pop
print(pop[-1])
My goal is to keep the best individual from the population, and always copy that to the next population. The best individual is returned by the fitness function. The individuals are OrderedDicts containing some values I try to optimize. What I just don't get is that the the print statement in the fourth line returns a different dictionary to the print statement in the last line. I was thinking it might have to do something with the OrderedDict since I never used those before. Does anyone have any idea?
You print
best_individualat the start of the loop. At the end of the loop you append it to the list and print the last element. The output of the print statements is not the same.They should be the same object, so if they're printing differently it means the object has been altered. Do any of the methods you've called alter any of the individuals in place (by reassigning keys)? I assume that the
best_individualis included in theselected_populationsince you're apparently selecting 50% of the population based on the fitness information. So ifself.crossoverorself.mutationassign keys on the objects that are passed in as arguments (parent1,parent2, andchild), then you could be accidentally altering thebest_individual.You might think that if
childis a new object then whatever is done to it inself.mutation(child)couldn't possibly be alteringbest_individual, but there's a potential gotcha I can guess at. You might accidentally be introducing aliasing between the parameters of the individuals. For example, ifself.crossover(parent1, parent2)is creating a new individual by randomly choosing each of its key values from eitherparent1orparent2, then the values in the new child will be the exact same objects as in the parent. If some of those values are mutable objects (like lists) and they are then altered in place inself.mutation(child)(instead of assigning new values for the keys), then when you mutate a child you'll also be mutating one of the parents, which could have beenbest_individual.If it's not obviously one of those things, some of this code must still be altering
best_individualsomehow (Ifpopcomes from a instance variable on whatever this class is that you haven't shown us and its contents are aliased rather than copies, then any method at all could potentially be getting into wherever thepopcame from and altering some of the individuals there, one of which isbest_individual). Rather than staring at the code and guessing (or asking other people on the internet to stare at only a part of the code and guess), you should try to narrow down exactly where thebest_individualis altered. If you know how to use the debugger, that's your best bet. If not (and you don't feel like learning now), just insertprint("1: ", best_individual)statements between every single line (change the numbers so you can tell where each print output came from). That should at least tell you the call wherebest_individualfirst changed; then you look inside the code of that and see what was happening there.