Ejemplo n.º 1
0
 def evolve_generation_speciated(self):
     # Clean out our previous species array
     species_list = []
     self.current_generation = {}
     # Find the fitness of all individuals of the previous generation,
     # And also assign a species to all of them
     for genome in self.previous_generation.values():
         genome.fitness = self.fitness_function(genome)
         genome_added = False
         for species in species_list:
             cd = Genome.compatibility_distance(self.previous_generation[species.representor], genome, self.config.PARAM_C1, self.config.PARAM_C2, self.config.PARAM_C3)
             if cd <= self.config.COMPATIBILITY_THRESHOLD:
                 species.add_genome(genome.id, genome.fitness)
                 genome_added = True
                 break
         if not genome_added:
             species_list.append(Species(genome.id, genome.fitness))
         species_list.sort(key=lambda species: species.total_fitness, reverse=True)
     # Recalculate the adjusted fitness based on species
     for species in species_list:
         for genome_id in species.genomes:
             self.previous_generation[genome_id].fitness /= species.count_genomes
     # Kill off low performing individuals
     fitness_sorted_genome_ids = [genome[0] for genome in sorted(self.previous_generation.items(), key=lambda genome: genome[1].fitness, reverse=True)]
     parents = fitness_sorted_genome_ids[:int(self.config.SELECTION_RATIO * self.config.POPULATION_SIZE)]
     for species in species_list:
         for genome_id in species.genomes:
             if genome_id not in parents:
                 species.genomes.remove(genome_id)
     species = [species for species in species_list if species]
     
     # Allocate child count per-species and create children
     total_fitness = reduce(lambda a, b: a + b, [s.total_fitness for s in species_list])
     if total_fitness > 0.0:
         allocation_ratio = self.config.POPULATION_SIZE / total_fitness
         per_species_allocation = [(index, int(species.total_fitness * allocation_ratio)) for index, species in enumerate(species_list)]
         # Create offspring to fill up remaining space by random mating and mutations based on species size
         for index, child_count in per_species_allocation:
             for _ in range(child_count):
                 parent1 = self.previous_generation[self.random.choice(species_list[index].genomes)]
                 parent2 = self.previous_generation[self.random.choice([genome for genome in species_list[index].genomes if genome != parent1])]
                 child = Genome.generate_offspring(parent1, self.max_id, self.random, self.node_classes, self.innovator, self.config, parent2)
                 self.current_generation[child.id] = child
     
     present_population_size = len(self.current_generation)
     while present_population_size <= self.config.POPULATION_SIZE:
         parent = self.previous_generation[self.random.choice(parents)]
         child = Genome.generate_offspring(parent, self.max_id, self.random, self.node_classes, self.innovator, self.config)
         self.current_generation[child.id] = child
         present_population_size += 1
         self.max_id += 1
     # Update all lists and perform logging
     self.previous_generation = self.current_generation