Beispiel #1
0
    def genome_distance(self, genome0, genome1):
        '''
		Computes genome distance between two genomes
		'''
        node_distance = 0.0
        # Determine node distance
        if genome0.nodes or genome1.nodes:
            # Number of disjoing nodes between genomes
            disjoint_nodes = 0
            # Count number of disjoint node genes between genomes
            for genome_1_node_key in iterkeys(genome1.nodes):
                if genome_1_node_key not in genome0.nodes:
                    disjoint_nodes += 1
            # Determine genetic distance between  individual node genes
            for genome_0_node_key, genome_0_node in iteritems(genome0.nodes):
                genome_1_node = genome1.nodes.get(genome_0_node_key)
                if genome_1_node is None:
                    disjoint_nodes += 1
                else:
                    # Homologous genes compute their own distance value.
                    node_distance += self.node_gene_distance(
                        genome_0_node, genome_1_node)
            # Find most number of nodes in either genome
            max_nodes = max(len(genome0.nodes), len(genome1.nodes))
            # Determine final node genetic distance
            node_distance = (node_distance +
                             (self.compatibility_disjoint_coefficient *
                              disjoint_nodes)) / max_nodes

        # Determine connection gene distance
        connection_distance = 0.0
        if genome0.connections or genome1.connections:
            disjoint_connections = 0
            for genome_1_conn_key in iterkeys(genome1.connections):
                if genome_1_conn_key not in genome0.connections:
                    disjoint_connections += 1

            for genome_0_conn_key, genome_0_conn in iteritems(
                    genome0.connections):
                genome_1_conn = genome1.connections.get(genome_0_conn_key)
                if genome_1_conn is None:
                    disjoint_connections += 1
                else:
                    # Homologous genes compute their own distance value.
                    connection_distance += self.connection_gene_distance(
                        genome_0_conn, genome_1_conn)

            max_conn = max(len(genome0.connections), len(genome1.connections))
            connection_distance = (connection_distance +
                                   (self.compatibility_disjoint_coefficient *
                                    disjoint_connections)) / max_conn

        distance = node_distance + connection_distance
        return distance
Beispiel #2
0
    def mutate_add_connection(self, gen=None):
        '''
		Mutation for adding a connection gene to the genome.

		gen -- optional argument for current generation mutation occurs
		'''
        # Gather possible target nodes and source nodes
        if not self.nodes:
            return
        possible_targets = list(iterkeys(self.nodes))
        target_key = choice(possible_targets)
        possible_sources = possible_targets + self.input_keys
        source_key = choice(possible_sources)
        # Determine if new connection creates cycles. Currently, only
        # 	supports feed forward networks
        if creates_cycle(self.connections, (source_key, target_key)):
            return
        # Ensure connection isn't duplicate
        if (source_key, target_key) in self.connections:
            self.connections[(source_key, target_key)].enabled = True
            return
        # Don't allow connections between two output nodes
        if source_key in self.output_keys and target_key in self.output_keys:
            return
        new_conn = self.create_connection(source_key, target_key)
Beispiel #3
0
    def mutate_delete_node(self, gen=None):
        '''
		Mutation for deleting a node gene to the genome.

		gen -- optional argument for current generation mutation occurs
		'''
        available_nodes = [
            k for k in iterkeys(self.nodes) if k not in self.output_keys
        ]
        if not available_nodes:
            return
        # Choose random node to delete
        del_key = np.random.choice(available_nodes)
        # Iterate through all connections and find connections to node
        conn_to_delete = set()
        for k, v in iteritems(self.connections):
            if del_key in v.key:
                conn_to_delete.add(v.key)
        for i in conn_to_delete:
            del self.connections[i]
        # Delete node key
        del self.nodes[del_key]
        return del_key
	def speciate(self,population,generation):
		'''
		Speciates a population.
		'''
		# Compatibility threshold
		compatibility_threshold = self.threshold
		# Set of unspeciated members of the population
		unspeciated = set(iterkeys(population))
		# Means of determining distances
		distances = GenomeDistanceCache()
		# New representatives and members of species
		new_representatives = {}
		new_members = {}
		# Traverse through set of species from last generation
		for sid, species in iteritems(self.species):
			# Candidates for current species representatives
			candidate_representatives = []
			# Traverese genomes in the unspeciated and check their distance
			# from the current species representative
			for gid in unspeciated:
				genome = population[gid]
				genome_distance = distances(species.representative, genome)
				candidate_representatives.append((genome_distance, genome))
			# The new representative for the current species is the 
			# closest to the current representative
			_, new_rep = min(candidate_representatives, key=lambda x: x[0])
			new_rid = new_rep.key
			new_representatives[sid] = new_rid
			new_members[sid] = [new_rid]
			unspeciated.remove(new_rid)

		# Partition the population in species based on genetic similarity
		while unspeciated:
			gid = unspeciated.pop()
			genome = population[gid]
			# Find the species with the most similar representative to the
			# 	current genome from the unspeciated set
			candidate_species = []
			# Traverse species and their representatives
			for sid, rid in iteritems(new_representatives):
				representative = population[rid]
				# Determine current genome's distance from representative
				genome_distance = distances(representative, genome)
				# If it's below threshold, add it to list for adding to the species
				if genome_distance < compatibility_threshold:
					candidate_species.append((genome_distance, sid))
			# Add current genome to the species its most genetically similar to
			if candidate_species:
				_, sid = min(candidate_species, key=lambda x: x[0])
				new_members[sid].append(gid)
			else:
				# No species is similar enough so we create a mnew species with
				# 	the current genome as its representative
				sid = next(self.species_indexer)
				new_representatives[sid] = gid
				new_members[sid] = [gid]
			# Update species collection based on new speciation
			self.genome_to_species = {}
			for sid, rid in iteritems(new_representatives):
				# Add species if not existing in current species set
				s = self.species.get(sid)
				if s is None:
					s = Species(sid, generation)
					self.species[sid] = s
				# Collect and add members to current species
				members = new_members[sid]
				for gid in members:
					self.genome_to_species[gid] = sid
				# Update current species members and represenative
				member_dict = {gid:population[gid] for gid in members}
				s.update(population[rid], member_dict)