def test_crossover(self): genome1 = Genome(self.genome_params) genome2 = Genome(self.genome_params) genome1.connect() genome2.connect() genome1.fitness = 5 genome2.fitness = 20 genome2.mutate() assert len(genome2.nodes) == 4 assert len(genome2.connection_genes) == 4 assert genome2.connection_genes[3].innovation_number == 4 disabled_gene = None for idx, cg in enumerate(genome2.connection_genes): if not cg.enabled: disabled_gene = idx break child = genome2.crossover(genome1, genome2) # child inherited fittest parent nodes assert len(child.nodes) == len(genome2.nodes) # should be of same length despite some being disjoint genes assert len(child.connection_genes) == len(genome2.connection_genes) # check child got disabled gene transferred assert not child.connection_genes[disabled_gene].enabled
def breed(self, species): performing_species = [] for s in species: # if not s.staleness > self.stagnation_params.max_stagnation: performing_species.append(s) if not performing_species: raise Exception() species_members_count = tuple( [len(s.members) for s in performing_species]) new_society = [] # use the best performing species, if any for idx, s in enumerate(performing_species): spec_members = s.members if species_members_count[idx] == 1: new_society.append(spec_members[0]) elif species_members_count[idx] == 2: parent1 = spec_members[0] parent2 = spec_members[1] if parent1.fitness < parent2.fitness: parent1, parent2 = parent2, parent1 new_society.append(parent1) offspring = Genome(self.genome_params) offspring.connect() offspring = offspring.crossover(parent1, parent2) offspring.mutate() new_society.append(offspring) else: added = 0 spec_members.sort(key=lambda e: e.fitness, reverse=True) if self.reproduction_params.elitism > 0: # this must be changed elite_top_idx = self.reproduction_params.elitism if not floor(species_members_count[idx] / 2) >= self.reproduction_params.elitism: elite_top_idx = 1 for elite in spec_members[:elite_top_idx]: new_society.append(elite) spec_members.remove(elite) added += 1 # use some sort of criteria to ensure # there'll be at least 2 parents breeding # otherwise it'll breed a genetically identical offspring # cull_count = max(round(self.reproduction_params.survival_threshold * len(spec_members)), 2) # # spec_members = spec_members[:cull_count] while added < species_members_count[idx]: r1 = random.randint(0, len(spec_members) - 1) r2 = random.randint(0, len(spec_members) - 1) parent1 = spec_members[r1] parent2 = spec_members[r2] offspring = Genome(self.genome_params) offspring.connect() offspring = offspring.crossover(parent1, parent2) offspring.mutate() new_society.append(offspring) added += 1 if len(new_society) > self.genome_params.population_size: new_society = new_society[:self.genome_params.population_size] return new_society