def test_create_offspring_pairs(self): agent_id_generator = AgentIDGeneratorSingleCore() config = NeatConfig() rnd = np.random.RandomState(1) # First 10 random values # rnd.randint(3) = 1 # rnd.randint(3) = 0 # rnd.randint(3) = 0 # rnd.randint(3) = 1 # rnd.randint(3) = 1 # rnd.randint(3) = 0 # rnd.randint(3) = 0 # rnd.randint(3) = 1 tuple_list = ss.create_offspring_pairs(self.species1, 4, agent_id_generator, self.generation, rnd, config) # Test tuples agent_id_generator = AgentIDGeneratorSingleCore() self.assertEqual(4, len(tuple_list)) self.assertEqual((self.agent2.id, self.agent1.id, agent_id_generator.get_agent_id()), tuple_list[0]) self.assertEqual((self.agent1.id, self.agent2.id, agent_id_generator.get_agent_id()), tuple_list[1]) self.assertEqual((self.agent2.id, self.agent1.id, agent_id_generator.get_agent_id()), tuple_list[2]) self.assertEqual((self.agent1.id, self.agent2.id, agent_id_generator.get_agent_id()), tuple_list[3])
def _build_new_generation(self, generation: Generation, innovation_number_generator: InnovationNumberGeneratorInterface, species_id_generator: SpeciesIDGeneratorSingleCore, agent_id_generator: AgentIDGeneratorSingleCore, config: NeatConfig) -> Generation: # Notify callback self._notify_reporters_callback(lambda r: r.on_reproduction_start(generation)) # Get the random generator for the new generation new_generation_seed = np.random.RandomState(generation.seed).randint(2 ** 24) rnd = np.random.RandomState(new_generation_seed) # Get the best agents, which will be copied later best_agents_genomes = gs.get_best_genomes_from_species(generation.species_list, config.species_size_copy_best_genome) # Get allowed species for reproduction generation = ss.update_fitness_species(generation) species_list = ss.get_allowed_species_for_reproduction(generation, config.species_stagnant_after_generations) # TODO handle error no species if len(species_list) <= 5: species_list = generation.species_list # assert len(species_list) >= 1 # Calculate the adjusted fitness values min_fitness = min([a.fitness for a in generation.agents]) max_fitness = max([a.fitness for a in generation.agents]) species_list = ss.calculate_adjusted_fitness(species_list, min_fitness, max_fitness) # Remove the low performing genomes species_list = ss.remove_low_genomes(species_list, config.percentage_remove_low_genomes) # Calculate offspring for species off_spring_list = ss.calculate_amount_offspring(species_list, config.population_size - len(best_agents_genomes)) # Calculate off spring combinations off_spring_pairs = [] for species, amount_offspring in zip(species_list, off_spring_list): off_spring_pairs += ss.create_offspring_pairs(species, amount_offspring, agent_id_generator, generation, rnd, config) # Notify innovation number generator, that a new generation is created innovation_number_generator.next_generation(generation.number) # Create a dictionary for easy access agent_dict = {agent.id: agent for agent in generation.agents} # Create new agents - fill initially with best agents new_agents = [Agent(agent_id_generator.get_agent_id(), genome) for genome in best_agents_genomes] # Create agents with crossover self._notify_reporters_callback(lambda r: r.on_compose_offsprings_start()) for parent1_id, parent2_id, child_id in off_spring_pairs: parent1 = agent_dict[parent1_id] parent2 = agent_dict[parent2_id] child_seed = (parent1.genome.seed + parent2.genome.seed) % 2 ** 24 rnd_child = np.random.RandomState(child_seed) # Perform crossover for to get the nodes and connections for the child if parent1.fitness > parent2.fitness: child_nodes, child_connections = rp.cross_over(parent1.genome, parent2.genome, rnd_child, config) else: child_nodes, child_connections = rp.cross_over(parent2.genome, parent1.genome, rnd_child, config) # Create child genome child_genome = Genome(child_seed, child_nodes, child_connections) # Mutate genome child_genome = rp.mutate_weights(child_genome, rnd_child, config) child_genome, _, _, _ = rp.mutate_add_node(child_genome, rnd_child, innovation_number_generator, config) child_genome, _ = rp.mutate_add_connection(child_genome, rnd_child, innovation_number_generator, config) child_agent = Agent(child_id, child_genome) new_agents.append(child_agent) # Notify callback end self._notify_reporters_callback(lambda r: r.on_compose_offsprings_end()) # TODO convert back # Select new representative existing_species = [ss.select_new_representative(species, rnd) for species in generation.species_list] # Reset members and fitness existing_species = [ss.reset_species(species) for species in existing_species] # existing_species = [ss.reset_species(species) for species in generation.species_list] # Sort members into species new_species_list = ss.sort_agents_into_species(existing_species, new_agents, species_id_generator, config) logger.info("Species IDs: {}".format([s.id_ for s in new_species_list])) logger.info("Species Mem: {}".format([len(s.members) for s in new_species_list])) # Filter out empty species new_species_list = ss.get_species_with_members(new_species_list) # Create new generation, notify callback and return new generation new_generation = Generation(generation.number + 1, new_generation_seed, new_agents, new_species_list) self._notify_reporters_callback(lambda r: r.on_reproduction_end(new_generation)) return new_generation