예제 #1
0
    def mutate(self) -> MutationReport:
        mutation_report = MutationReport()

        if random.random() > self.mutation_chance:
            return mutation_report

        range = self.end_range - self.start_range

        if random.random() < 0.25:
            # random reset
            new_current_value = random.uniform(self.start_range,
                                               self.end_range)
            mutation_report += self.name + " changed from " + repr(
                self.current_value) + " to " + repr(new_current_value)

            self.current_value = new_current_value

        else:
            # random deviation
            deviation = random.normalvariate(0, range / 8)
            new_current_value = self.current_value + deviation
            new_current_value = self.start_range + (
                (new_current_value - self.start_range) % range)

            mutation_report += self.name + " deviated from " + repr(
                self.current_value) + " to " + repr(new_current_value)
            self.current_value = new_current_value

        if mutation_report is None:
            raise Exception("none mutation report in " + self.name)

        # print("returning from cont var mutagen: ", mutation_report)

        return mutation_report
예제 #2
0
    def mutate(self) -> MutationReport:
        mutation_report = MutationReport()

        my_weighting = self.probability_weightings[self.options.index(self())]
        my_relative_weighting = my_weighting / sum(self.probability_weightings)
        normalised_weighting = len(self.options)*my_relative_weighting
        effective_mutation_chance = self.mutation_chance * 1.0/ normalised_weighting

        """
            if the probability weightings of an option are not equal, then the mutation rates 
            should be adjusted such that: if the current option value is weighted less - the option 
            is more likely to change, and if the current option value is highly weighted - the option 
            should be less likely to change
        """

        if random.random() < effective_mutation_chance:
            if len(self.options) < 2:
                raise Exception("too few options to mutate")

            new_value = random.choices(self.options, weights=self.probability_weightings)[0]

            while new_value == self():
                new_value = random.choices(self.options, weights=self.probability_weightings)[0]

            mutation_report += self.name + " changed from " + repr(self.current_value) + " to " + repr(new_value)
            self.current_value = new_value

        return mutation_report + self.mutate_sub_mutagens()
예제 #3
0
    def mutate_base_genome(self,
                           genome: Genome,
                           mutation_record: MutationRecords,
                           add_node_chance: float,
                           add_connection_chance: float,
                           allow_disabling_connections: bool = True):
        """performs base neat genome mutations, as well as node and genome property mutations"""
        mutation_report = MutationReport()

        if random.random() < add_node_chance:
            if self.add_node_mutation(genome, mutation_record):
                mutation_report.nodes_added += 1

        if random.random() < add_connection_chance:
            if self.add_connection_mutation(genome, mutation_record):
                mutation_report.connections_created += 1

        if allow_disabling_connections:
            """randomly deactivates and reactivates connections"""
            for connection in genome.connections.values():
                orig_conn = copy.deepcopy(connection)
                result = connection.mutate(
                )  # this is the call which enables/disables connections

                if result.check_mutated():
                    """the connection was mutated"""
                    # If mutation made the genome invalid then undo it
                    if not genome.validate():
                        """
                            disabling the connection lead to a disconnected graph
                            or enabling the connection lead to a cycle
                            - undoing this mutation
                        """
                        genome.connections[orig_conn.id] = orig_conn
                    else:
                        """mutation is valid"""
                        if connection.enabled():
                            mutation_report.connections_enabled += 1
                        else:
                            mutation_report.connections_disabled += 1

        for node in genome.nodes.values():
            """mutates node properties"""
            mutation_report += node.mutate()

        for mutagen in genome.get_all_mutagens():
            """mutates the genome level properties"""
            report = mutagen.mutate()
            if report is None:
                raise Exception("none report returned from mutating " +
                                mutagen.name + ", " + repr(mutagen))
            mutation_report += report

        return mutation_report
예제 #4
0
    def forget_da_scheme(self, genome: BlueprintGenome) -> MutationReport:
        mutation_report = MutationReport()

        if not config.evolve_da_pop:
            # blueprint tethered da schemes should not be forgotten by their da
            return mutation_report

        if random.random() < config.da_link_forget_chance:
            genome.da = None
            genome._da_id = -1
            mutation_report += "forgot da scheme link"

        return mutation_report
예제 #5
0
    def mutate_species_numbers(self, genome) -> MutationReport:
        mutation_report = MutationReport()
        import src.main.singleton as Singleton

        for node in genome.nodes.values():
            if type(node) != BlueprintNode:
                continue
            if random.random() < config.blueprint_node_species_switch_chance:
                possible_species_ids = [spc.id for spc in Singleton.instance.module_population.species]
                new_species_id = random.choice(possible_species_ids)
                mutation_report+="changed species number of node " + str(node.id) + " from " + str(node.species_id) \
                                 + " to " + str(new_species_id)
                node.species_id = new_species_id

        return mutation_report
예제 #6
0
    def forget_module_mappings_mutation(self, genome: BlueprintGenome) -> MutationReport:
        mutation_report = MutationReport()

        if config.use_module_retention and random.random()<config.module_map_forget_mutation_chance:
            choices = list(set([node.species_id for node in genome.get_fully_connected_blueprint_nodes_iter() if node.linked_module_id != -1]))
            if len(choices) == 0:
                return mutation_report

            species_id = random.choice(choices)
            for node in genome.get_blueprint_nodes_iter():
                if node.species_id == species_id:
                    node.linked_module_id = -1  # forget the link. will be sampled fresh next cycle

            mutation_report += "forgot module mapping for species " + str(species_id)

        return mutation_report
예제 #7
0
    def mutate(self) -> MutationReport:
        mutation_report = MutationReport()

        if random.random() > self.mutation_chance:
            return mutation_report

        range = self.end_range - self.start_range

        if range == 0:
            raise Exception("zero range on mutagen " + repr(self) +
                            " start = " + repr(self.start_range) + " end = " +
                            repr(self.end_range))

        if random.random() < 0.25:
            # random reset
            new_current_value = random.randint(self.start_range,
                                               self.end_range)
            change_type = " changed"

        else:
            # random deviation
            deviation = random.normalvariate(0, range / 8)
            new_current_value = self.current_value + int(deviation)
            change_type = " deviated"

        # making sure value changes
        if new_current_value == self.current_value:
            new_current_value = self.current_value + random.choice([0, 1])

        new_current_value = self.start_range + (
            (new_current_value - self.start_range) % range)
        if new_current_value % 1 != 0:
            raise Exception("non natural number mutated in int variable")

        mutation_report += self.name + change_type + " from " + repr(
            self.current_value) + " to " + repr(new_current_value)
        self.current_value = new_current_value

        # print("returning from int var mutagen: ", mutation_report)

        return mutation_report
예제 #8
0
    def mutate_node_types(self, genome: Genome) -> MutationReport:
        """
        chance to change nodes from blueprint nodes to module nodes and visa versa
        """
        mutation_report = MutationReport()

        if random.random() < config.blueprint_node_type_switch_chance:
            """chose 1 node to change type"""
            node: Node = random.choice(list(genome.nodes.values()))
            if type(node) == BlueprintNode:
                """change node to a module node"""
                module_node = ModuleNode(node.id, node.node_type)
                genome.nodes[module_node.id] = module_node
                mutation_report += "swapped blueprint node for a module node"

            if type(node) == ModuleNode:
                """change node back to a blueprint node"""
                blueprint_node = BlueprintNode(node.id, node.node_type)
                genome.nodes[blueprint_node.id] = blueprint_node
                mutation_report += "swapped module node for a blueprint node"

        return mutation_report
예제 #9
0
    def mutate_sub_mutagens(self) -> MutationReport:
        mutation_report = MutationReport()
        for sub in self.get_submutagens():
            mutation_report += sub.mutate()

        return mutation_report
예제 #10
0
파일: gene.py 프로젝트: sash-a/CoDeepNEAT
 def mutate(self) -> MutationReport:
     report = MutationReport()
     for mutagen in self.get_all_mutagens():
         report += mutagen.mutate()
     return report