Exemple #1
0
    def test_genome(self):
        genome_empty = Genome(20)
        self.assertEqual(20, genome_empty.seed)
        self.assertEqual([], genome_empty.nodes)

        node_list = [
            Node(2,
                 NodeType.INPUT,
                 bias=0.5,
                 activation_function=lambda x: x + 1,
                 x_position=0),
            Node("node_number",
                 NodeType.OUTPUT,
                 bias=0.4,
                 activation_function=lambda x: x + 1,
                 x_position=1)
        ]

        connection_list = [
            Connection(1, 2, 3, 0.5, True),
            Connection("connection_number", 2, 3, 0.7, False)
        ]

        genome = Genome(40, node_list, connection_list)
        self.assertEqual(40, genome.seed)
        self.assertEqual(node_list, genome.nodes)
        self.assertEqual(connection_list, genome.connections)
    def setUp(self) -> None:
        self.inn_generator = InnovationNumberGeneratorSingleCore()
        self.rnd = np.random.RandomState(1)

        self.node_input1 = Node(self.inn_generator.get_node_innovation_number(), NodeType.INPUT, 0, step_activation, 0)
        self.node_input2 = Node(self.inn_generator.get_node_innovation_number(), NodeType.INPUT, 0, step_activation, 0)
        self.node_output1 = Node(self.inn_generator.get_node_innovation_number(), NodeType.OUTPUT, 1.2, step_activation,
                                 1)
        self.node_hidden1 = Node(self.inn_generator.get_node_innovation_number(), NodeType.HIDDEN, 1.3, step_activation,
                                 0.5)
        self.nodes = [self.node_input1, self.node_input2, self.node_output1, self.node_hidden1]

        self.connection1 = Connection(self.inn_generator.get_connection_innovation_number(),
                                      input_node=self.node_input1.innovation_number,
                                      output_node=self.node_output1.innovation_number, weight=-2.1, enabled=True)
        self.connection2 = Connection(self.inn_generator.get_connection_innovation_number(),
                                      input_node=self.node_input2.innovation_number,
                                      output_node=self.node_output1.innovation_number, weight=-1.2, enabled=True)
        self.connection3 = Connection(self.inn_generator.get_connection_innovation_number(),
                                      input_node=self.node_input1.innovation_number,
                                      output_node=self.node_hidden1.innovation_number, weight=0.6, enabled=True)
        self.connection4 = Connection(self.inn_generator.get_connection_innovation_number(),
                                      input_node=self.node_hidden1.innovation_number,
                                      output_node=self.node_output1.innovation_number, weight=0, enabled=False)
        self.connections = [self.connection1, self.connection2, self.connection3, self.connection4]

        self.genome = Genome(1, self.nodes, connections=self.connections)
    def test_deep_copy_connection(self):
        original_connection = Connection(124, 10, 20, 1.2, True)
        original_connection_str = Connection("124124", 12, 22, 0.8, False)

        copied_connection = deep_copy_connection(original_connection)
        copied_connection_str = deep_copy_connection(original_connection_str)

        self.compare_connections(original_connection, copied_connection)
        self.compare_connections(original_connection_str, copied_connection_str)
def mutate_add_node(
        genome: Genome, rnd: np.random.RandomState,
        generator: InnovationNumberGeneratorInterface,
        config: NeatConfig) -> (Genome, Node, Connection, Connection):
    """
    Add with a given probability from the config a new node to the genome.
    A random connections is selected, which will be disabled. A new node will be placed between the in and out node of
    the connection. Then two new connections will be created, one which leads into the new node (weight=1) and one out
    (weight = weight of the disabled connection).
    :param genome: the genome that should be modified
    :param rnd: a random generator to determine if, the genome is mutated, and how
    :param generator: a generator for innovation number for nodes and connections
    :param config: a config that specifies the mutation params
    :return: the modified genome, as well as the generated node and the two connections (if they were mutated)
    """
    # Check if node should mutate
    if rnd.uniform(0, 1) > config.probability_mutate_add_node:
        return genome, None, None, None

    selected_connection = genome.connections[rnd.randint(
        0, len(genome.connections))]
    selected_connection.enabled = False

    in_node = next(x for x in genome.nodes
                   if x.innovation_number == selected_connection.input_node)
    out_node = next(x for x in genome.nodes
                    if x.innovation_number == selected_connection.output_node)

    # Select activation function either from one of the nodes
    new_node_activation = in_node.activation_function if rnd.uniform(
        0, 1) <= 0.5 else out_node.activation_function
    new_node_x_position = (in_node.x_position + out_node.x_position) / 2
    new_node = Node(
        generator.get_node_innovation_number(in_node,
                                             out_node), NodeType.HIDDEN,
        rnd.uniform(low=config.bias_initial_min, high=config.bias_initial_max),
        new_node_activation, new_node_x_position)

    new_connection_in = Connection(generator.get_connection_innovation_number(
        in_node, new_node),
                                   in_node.innovation_number,
                                   new_node.innovation_number,
                                   weight=1,
                                   enabled=True)
    new_connection_out = Connection(generator.get_connection_innovation_number(
        new_node, out_node),
                                    new_node.innovation_number,
                                    out_node.innovation_number,
                                    weight=selected_connection.weight,
                                    enabled=True)

    genome.nodes.append(new_node)
    genome.connections.append(new_connection_in)
    genome.connections.append(new_connection_out)

    return genome, new_node, new_connection_in, new_connection_out
    def test_set_new_genome_weights(self):
        original_genome = Genome(123,
                                 [Node(1, NodeType.INPUT, 1.1, step_activation, 0)],
                                 [Connection(124, 10, 20, 1.2, True),
                                  Connection("124124", 12, 22, 0.8, False)])

        config = NeatConfig(connection_initial_min_weight=-10, connection_initial_max_weight=10)
        new_genome = set_new_genome_weights(original_genome, np.random.RandomState(2), config=config)
        # First 3 random values
        # 1. -1.2801019571599248
        # 2. -9.481475363442174
        # 3. -1.293552147634463

        self.assertAlmostEqual(-1.2801019571599248, new_genome.connections[0].weight, delta=0.00000001)
        self.assertAlmostEqual(-9.481475363442174, new_genome.connections[1].weight, delta=0.00000001)
    def test_create_initial_generation_genome(self):
        genome = Genome(20, [
            Node("abc", NodeType.INPUT, 0.3, step_activation, 0),
            Node("def", NodeType.OUTPUT, 0.4, step_activation, 1)
        ], [
            Connection("x", "abc", "def", 1.0, True),
            Connection("y", "def", "abc", -5, True)
        ])

        generation = gs.create_initial_generation_genome(
            genome,
            InnovationNumberGeneratorSingleCore(),
            SpeciesIDGeneratorSingleCore(),
            AgentIDGeneratorSingleCore(),
            NeatConfig(population_size=3),
            seed=1)

        self.assertEqual(3, len(generation.agents))
        self.assertEqual(0, generation.number)
        self.assertEqual(1, len(generation.species_list))
        self.assertEqual(3, len(generation.species_list[0].members))
        self.assertEqual(1, generation.seed)

        # First three random numbers
        # 1 - 12710949
        # 2 - 4686059
        # 3 - 6762380
        self.assertEqual(12710949, generation.agents[0].genome.seed)
        self.assertEqual(4686059, generation.agents[1].genome.seed)
        self.assertEqual(6762380, generation.agents[2].genome.seed)

        for node1, node2, node3, i in zip(generation.agents[0].genome.nodes,
                                          generation.agents[1].genome.nodes,
                                          generation.agents[2].genome.nodes,
                                          range(3)):
            self.assertEqual(node1.innovation_number, node2.innovation_number)
            self.assertEqual(node2.innovation_number, node3.innovation_number)
            self.assertEqual(node3.innovation_number, i)

        for connection1, connection2, connection3, i in zip(
                generation.agents[0].genome.connections,
                generation.agents[1].genome.connections,
                generation.agents[2].genome.connections, range(3)):
            self.assertEqual(connection1.innovation_number,
                             connection2.innovation_number)
            self.assertEqual(connection2.innovation_number,
                             connection3.innovation_number)
            self.assertEqual(connection3.innovation_number, i)
def deep_copy_connection(connection: Connection) -> Connection:
    """
    Make a deep copy of the given connection and return the new instance
    :param connection: the connection to be copied
    :return: the newly created connection
    """
    return Connection(connection.innovation_number, connection.input_node,
                      connection.output_node, connection.weight,
                      connection.enabled)
Exemple #8
0
    def test_connection(self):
        connection = Connection(10, 2, 3, 0.4, False)
        self.assertEqual(10, connection.innovation_number)

        self.assertEqual(2, connection.input_node)
        self.assertEqual(3, connection.output_node)
        self.assertEqual(0.4, connection.weight)
        self.assertFalse(connection.enabled)

        connection2 = Connection(
            "test_number",
            12,
            13,
            0.6,
            True,
        )
        self.assertEqual("test_number", connection2.innovation_number)
        self.assertEqual(12, connection2.input_node)
        self.assertEqual(13, connection2.output_node)
        self.assertEqual(0.6, connection2.weight)
        self.assertTrue(connection2.enabled)
    def test_deep_copy_genome(self):
        original_genome = Genome(123,
                                 [Node(1, NodeType.INPUT, 1.1, step_activation, 0),
                                  Node("asfaf", NodeType.OUTPUT, 1.2, step_activation, 1)],
                                 [Connection(124, 10, 20, 1.2, True),
                                  Connection("124124", 12, 22, 0.8, False)])

        copied_genome = deep_copy_genome(original_genome)

        # Check if genomes dont have the same id
        self.assertIsNotNone(original_genome)
        self.assertIsNotNone(copied_genome)
        self.assertNotEqual(id(original_genome), id(copied_genome))

        # Compare values
        self.assertEqual(original_genome.seed, copied_genome.seed)

        for original_node, copied_node in zip(original_genome.nodes, copied_genome.nodes):
            self.compare_nodes(original_node, copied_node)

        for original_connection, copied_connection in zip(original_genome.connections, copied_genome.connections):
            self.compare_connections(original_connection, copied_connection)
    def test_build_generation_from_genome(self):
        initial_genome = Genome(20, [
            Node(1, NodeType.INPUT, 0, step_activation, 0),
            Node(2, NodeType.OUTPUT, 0.4, step_activation, 1)
        ], [Connection(1, 1, 2, 1.0, True),
            Connection(2, 1, 2, -5, True)])

        rnd = np.random.RandomState(1)
        generation = gs._build_generation_from_genome(
            initial_genome, SpeciesIDGeneratorSingleCore(),
            AgentIDGeneratorSingleCore(), 19, rnd,
            NeatConfig(population_size=3))

        self.assertEqual(3, len(generation.agents))
        self.assertEqual(0, generation.number)
        self.assertEqual(1, len(generation.species_list))
        self.assertEqual(3, len(generation.species_list[0].members))
        self.assertEqual(19, generation.seed)

        # First three random numbers
        # 1 - 12710949
        # 2 - 4686059
        # 3 - 6762380
        self.assertEqual(12710949, generation.agents[0].genome.seed)
        self.assertEqual(4686059, generation.agents[1].genome.seed)
        self.assertEqual(6762380, generation.agents[2].genome.seed)

        # Check if every weight and bias is not equal to 0
        for agent, i in zip(generation.agents, range(len(generation.agents))):
            genome = agent.genome
            self.assertEqual(i, agent.id)
            for node in genome.nodes:
                # Input nodes can have bias 0
                if node.node_type == NodeType.INPUT:
                    continue
                self.assertNotAlmostEqual(0, node.bias, delta=0.00000000001)

            for conn in genome.connections:
                self.assertNotAlmostEqual(0, conn.weight, delta=0.00000000001)
    def test_randomize_weight_bias(self):
        genome = Genome(20, [
            Node(1, NodeType.INPUT, 0.0, step_activation, 0),
            Node(2, NodeType.OUTPUT, 0.0, step_activation, 1)
        ], [Connection(3, 1, 2, 0, True),
            Connection(4, 2, 1, 0, True)])

        config = NeatConfig(bias_initial_min=1,
                            bias_initial_max=2,
                            connection_initial_min_weight=3,
                            connection_initial_max_weight=4)
        randomized_genome = gs._randomize_weight_bias(genome,
                                                      np.random.RandomState(1),
                                                      config)

        for node in randomized_genome.nodes:
            if node.node_type == NodeType.INPUT:
                self.assertEqual(0, node.bias)
            else:
                self.assertTrue(1 <= node.bias <= 2)

        for conn in randomized_genome.connections:
            self.assertTrue(3 <= conn.weight <= 4)
    def test_evaluate_genome_structure(self):
        genome = Genome(0, [
            Node(0, NodeType.INPUT, 0, modified_sigmoid_activation, 0),
            Node(1, NodeType.INPUT, 0, modified_sigmoid_activation, 0),
            Node(2, NodeType.OUTPUT, 0, modified_sigmoid_activation, 1),
            Node(3, NodeType.HIDDEN, 0, modified_sigmoid_activation, 0.5),
            Node(4, NodeType.HIDDEN, 0, modified_sigmoid_activation, 0.5)
        ], [
            Connection(1, 0, 3, 0.1, True),
            Connection(2, 1, 3, 0.1, True),
            Connection(3, 0, 4, 0.1, True),
            Connection(4, 1, 4, 0.1, True),
            Connection(5, 3, 2, 0.1, True),
            Connection(6, 4, 2, 0.1, True)
        ])
        self.optimizer_single.evaluate_genome_structure(
            genome, self.challenge, self.config, 1)

        expected_generation_number = 10

        # Test callback functions
        self.assertEqual(1, self.challenge.initialization_count)

        # Reproduction functions
        self.assertEqual(expected_generation_number,
                         self.callback.on_reproduction_start_count)
        self.assertEqual(expected_generation_number,
                         self.callback.on_compose_offsprings_start_count)
        self.assertEqual(expected_generation_number,
                         self.callback.on_compose_offsprings_end_count)
        self.assertEqual(expected_generation_number,
                         self.callback.on_reproduction_start_count)

        # Evaluation loop
        self.assertEqual(expected_generation_number + 1,
                         self.callback.on_generation_evaluation_start_count)
        self.assertEqual(
            (1 + expected_generation_number) * self.config.population_size,
            self.callback.on_agent_evaluation_start_count)
        self.assertEqual(
            (1 + expected_generation_number) * self.config.population_size,
            self.callback.on_agent_evaluation_end_count)
        self.assertEqual(expected_generation_number + 1,
                         self.callback.on_generation_evaluation_end_count)
        self.assertEqual(expected_generation_number,
                         self.callback.finish_evaluation_count)

        # Finish evaluation
        self.assertEqual(1, self.callback.on_finish_count)
        self.assertEqual(1, self.callback.on_cleanup_count)

        # Check generated networks
        self.assertEqual(self.config.population_size,
                         len(self.callback.finish_generation.agents))
def create_genome_structure(
        amount_input_nodes: int, amount_output_nodes: int, activation_function,
        config: NeatConfig,
        generator: InnovationNumberGeneratorInterface) -> Genome:
    """
    Create an initial genome struture with the given amount of input and output nodes. The nodes will be fully
    connected,     that means, that every input node will be connected to every output node. The bias of the nodes, as
    well as the connections will have the value 0! They must be set before usage
    :param amount_input_nodes: the amount of input nodes, that will be placed in the genome
    :param amount_output_nodes: the amount of output nodes, that will be placed in the genome
    :param activation_function: the activation function for the nodes
    :param config: the config
    :param generator: for the innovation numbers for nodes and connections
    :return: the generated genome
    """
    input_nodes = [
        Node(generator.get_node_innovation_number(),
             NodeType.INPUT,
             bias=0,
             activation_function=activation_function,
             x_position=0.0) for _ in range(amount_input_nodes)
    ]

    output_nodes = [
        Node(generator.get_node_innovation_number(),
             NodeType.OUTPUT,
             bias=0,
             activation_function=activation_function,
             x_position=1.0) for _ in range(amount_output_nodes)
    ]

    connections = []
    for input_node in input_nodes:
        for output_node in output_nodes:
            connections.append(
                Connection(innovation_number=generator.
                           get_connection_innovation_number(),
                           input_node=input_node.innovation_number,
                           output_node=output_node.innovation_number,
                           weight=0,
                           enabled=True))

    return Genome(seed=None,
                  nodes=input_nodes + output_nodes,
                  connections=connections)
Exemple #14
0
    def setUp(self) -> None:
        seed = np.random.RandomState().randint(2**24)
        rnd = np.random.RandomState(seed)

        self.genome = Genome(seed, [
            Node(1, NodeType.INPUT, rnd.uniform(-5, 5), step_activation, 0.5),
            Node(2, NodeType.OUTPUT, rnd.uniform(-5, 5),
                 modified_sigmoid_activation, 0.5),
            Node(3, NodeType.HIDDEN, rnd.uniform(-5, 5), step_activation, 0.5),
            Node(4, NodeType.HIDDEN, rnd.uniform(-5, 5), step_activation, 0.5),
        ], [
            Connection(1, 1, 2, rnd.uniform(-5, 5), True),
            Connection(2, 1, 4, rnd.uniform(-5, 5), True),
            Connection(3, 1, 3, rnd.uniform(-5, 5), True),
            Connection(4, 3, 2, rnd.uniform(-5, 5), True),
            Connection(5, 4, 2, rnd.uniform(-5, 5), True),
            Connection(6, 2, 2, rnd.uniform(-5, 5), False),
        ])
Exemple #15
0
    def evaluate_fix_structure(self,
                               optimizer: NeatOptimizer,
                               seed: int = None):
        optimizer.register_callback(self)
        config = NeatConfig(allow_recurrent_connections=False,
                            population_size=150,
                            compatibility_threshold=3,
                            connection_min_weight=-5,
                            connection_max_weight=5,
                            bias_min=-5,
                            bias_max=5,
                            probability_mutate_add_node=0,
                            probability_mutate_add_connection=0)

        # Create random seed, if none is specified
        if seed is None:
            seed = np.random.RandomState().randint(2**24)
        logger.info("Used Seed: {}".format(seed))

        genome = Genome(0, [
            Node(0, NodeType.INPUT, 0, modified_sigmoid_activation, 0),
            Node(1, NodeType.INPUT, 0, modified_sigmoid_activation, 0),
            Node(2, NodeType.OUTPUT, 0, modified_sigmoid_activation, 1),
            Node(3, NodeType.HIDDEN, 0, modified_sigmoid_activation, 0.5),
            Node(4, NodeType.HIDDEN, 0, modified_sigmoid_activation, 0.5)
        ], [
            Connection(1, 0, 3, 0.1, True),
            Connection(2, 1, 3, 0.1, True),
            Connection(3, 0, 4, 0.1, True),
            Connection(4, 1, 4, 0.1, True),
            Connection(5, 3, 2, 0.1, True),
            Connection(6, 4, 2, 0.1, True)
        ])

        optimizer.evaluate_genome_structure(genome_structure=genome,
                                            challenge=ChallengeXOR(),
                                            config=config,
                                            seed=seed)
    def setUp(self) -> None:
        self.config = NeatConfig(compatibility_factor_matching_genes=1,
                                 compatibility_factor_disjoint_genes=2,
                                 compatibility_threshold=2.5,
                                 compatibility_genome_size_threshold=0,
                                 population_size=8)

        self.g1_nodes = [
            Node(1, NodeType.INPUT, 0, step_activation, 0),
            Node(2, NodeType.INPUT, 0, step_activation, 0),
            Node(3, NodeType.OUTPUT, 1.2, step_activation, 1),
            Node(4, NodeType.HIDDEN, 1.5, step_activation, 0.5),
            Node(6, NodeType.HIDDEN, 0.5, step_activation, 0.5),
            Node(7, NodeType.HIDDEN, 0.2, step_activation, 0.25)
        ]
        self.g1_connections = [
            Connection(1, 1, 3, 1.2, True),
            Connection(2, 2, 3, 0.5, False),
            Connection(3, 1, 4, -1.2, True),
            Connection(4, 4, 3, 0.2, True),
            Connection(5, 2, 6, 2.0, True),
            Connection(6, 6, 3, -1.1, False)
        ]
        self.g1 = Genome(1, self.g1_nodes, self.g1_connections)

        self.g2_nodes = [
            Node(1, NodeType.INPUT, 0, step_activation, 0),
            Node(2, NodeType.INPUT, 0, step_activation, 0),
            Node(3, NodeType.OUTPUT, 0.2, step_activation, 1),
            Node(4, NodeType.HIDDEN, 1.2, step_activation, 0.5),
            Node(5, NodeType.HIDDEN, 2.8, step_activation, 0.5)
        ]

        self.g2_connections = [
            Connection(1, 1, 3, 0.8, True),
            Connection(2, 2, 3, 1.5, True),
            Connection(3, 1, 4, 1.2, True),
            Connection(4, 4, 3, 3.2, True),
            Connection(6, 6, 3, -1.1, False),
            Connection(7, 6, 3, -0.1, False),
            Connection(8, 1, 4, -1.1, False)
        ]
        self.g2 = Genome(2, self.g2_nodes, self.g2_connections)

        self.agent1 = Agent(1, self.g1)
        self.agent1.fitness = 1
        self.agent2 = Agent(2, self.g2)
        self.agent2.fitness = 2

        # Add some more agents, and complete species
        self.inno_num_generator = InnovationNumberGeneratorSingleCore()
        self.species_id_generator = SpeciesIDGeneratorSingleCore()
        self.genome3 = gs.create_genome_structure(2, 1, step_activation,
                                                  self.config,
                                                  self.inno_num_generator)
        self.genome4 = gs.create_genome_structure(2, 1, step_activation,
                                                  self.config,
                                                  self.inno_num_generator)
        self.genome5 = gs.create_genome_structure(2, 1, step_activation,
                                                  self.config,
                                                  self.inno_num_generator)
        self.genome6 = gs.create_genome_structure(2, 1, step_activation,
                                                  self.config,
                                                  self.inno_num_generator)
        self.genome7 = gs.create_genome_structure(2, 1, step_activation,
                                                  self.config,
                                                  self.inno_num_generator)
        self.genome8 = gs.create_genome_structure(2, 1, step_activation,
                                                  self.config,
                                                  self.inno_num_generator)

        self.agent3 = Agent(3, self.genome3)
        self.agent3.fitness = 3
        self.agent4 = Agent(4, self.genome4)
        self.agent4.fitness = 4
        self.agent5 = Agent(5, self.genome5)
        self.agent5.fitness = 5
        self.agent6 = Agent(6, self.genome6)
        self.agent6.fitness = 6
        self.agent7 = Agent(7, self.genome7)
        self.agent7.fitness = 7
        self.agent8 = Agent(8, self.genome8)
        self.agent8.fitness = 8

        self.species1 = Species(self.species_id_generator.get_species_id(),
                                self.agent1.genome,
                                [self.agent1, self.agent2, self.agent3],
                                max_species_fitness=1.5,
                                generation_max_species_fitness=10)
        self.species2 = Species(self.species_id_generator.get_species_id(),
                                self.agent4.genome,
                                [self.agent4, self.agent5, self.agent6],
                                max_species_fitness=7,
                                generation_max_species_fitness=5)
        self.species3 = Species(self.species_id_generator.get_species_id(),
                                self.agent6.genome, [self.agent7, self.agent8],
                                max_species_fitness=0,
                                generation_max_species_fitness=6)

        self.generation = Generation(
            21,
            2,
            agents=[
                self.agent1, self.agent2, self.agent3, self.agent4,
                self.agent5, self.agent6, self.agent7, self.agent8
            ],
            species_list=[self.species1, self.species2, self.species3])
    def setUp(self) -> None:
        self.feed_forward_hidden_bias = -0.5
        self.feed_forward_output_bias = -0.6

        self.nodes_feed_forward = [
            Node(1, NodeType.INPUT, 0, step_activation, x_position=0),
            Node(2, NodeType.INPUT, 0, step_activation, x_position=0),
            Node(3, NodeType.INPUT, 0, step_activation, x_position=0),
            Node(4,
                 NodeType.OUTPUT,
                 self.feed_forward_output_bias,
                 step_activation,
                 x_position=1),
            Node(15,
                 NodeType.HIDDEN,
                 self.feed_forward_hidden_bias,
                 step_activation,
                 x_position=0.5),
        ]

        self.connections_feed_forward = [
            Connection(innovation_number=5,
                       input_node=1,
                       output_node=4,
                       weight=0.5,
                       enabled=True),
            Connection(innovation_number=16,
                       input_node=1,
                       output_node=15,
                       weight=-0.4,
                       enabled=True),
            Connection(innovation_number=17,
                       input_node=15,
                       output_node=4,
                       weight=2.0,
                       enabled=True),
            Connection(innovation_number=18,
                       input_node=2,
                       output_node=15,
                       weight=-1.0,
                       enabled=True),
            Connection(innovation_number=6,
                       input_node=2,
                       output_node=4,
                       weight=-15.0,
                       enabled=False),
            Connection(innovation_number=19,
                       input_node=3,
                       output_node=15,
                       weight=2.0,
                       enabled=True),
            Connection(innovation_number=19,
                       input_node=3,
                       output_node=4,
                       weight=15.0,
                       enabled=False)
        ]

        self.genome_feed_forward = Genome(10, self.nodes_feed_forward,
                                          self.connections_feed_forward)
        # Truth table for the neural network above
        # X Y Z
        # Input 0 0 0: Result: 0.0
        # Input 0 0 1: Result: 1.0
        # Input 0 1 0: Result: 0.0
        # Input 0 1 1: Result: 1.0
        # Input 1 0 0: Result: 0.0
        # Input 1 0 1: Result: 1.0
        # Input 1 1 0: Result: 0.0
        # Input 1 1 1: Result: 1.0

        self.net_feed_forward = BasicNeuralNetwork()

        self.nodes_recurrent = [
            Node(1,
                 NodeType.INPUT,
                 0,
                 modified_sigmoid_activation,
                 x_position=0),
            Node(2,
                 NodeType.INPUT,
                 0,
                 modified_sigmoid_activation,
                 x_position=0),
            Node(3,
                 NodeType.INPUT,
                 0,
                 modified_sigmoid_activation,
                 x_position=0),
            Node(4,
                 NodeType.OUTPUT,
                 -1.0,
                 modified_sigmoid_activation,
                 x_position=1),
            Node(10,
                 NodeType.HIDDEN,
                 -0.6,
                 modified_sigmoid_activation,
                 x_position=0.5),
            Node(15,
                 NodeType.HIDDEN,
                 -1.2,
                 modified_sigmoid_activation,
                 x_position=0.5),
        ]

        self.connections_recurrent = [
            Connection(innovation_number=11,
                       input_node=1,
                       output_node=10,
                       weight=0.5,
                       enabled=True),
            Connection(innovation_number=12,
                       input_node=2,
                       output_node=10,
                       weight=-0.3,
                       enabled=True),
            Connection(innovation_number=22,
                       input_node=10,
                       output_node=10,
                       weight=1.5,
                       enabled=True),
            Connection(innovation_number=21,
                       input_node=15,
                       output_node=10,
                       weight=-0.1,
                       enabled=True),
            Connection(innovation_number=16,
                       input_node=2,
                       output_node=15,
                       weight=2.0,
                       enabled=True),
            Connection(innovation_number=17,
                       input_node=3,
                       output_node=15,
                       weight=-1.6,
                       enabled=True),
            Connection(innovation_number=20,
                       input_node=10,
                       output_node=15,
                       weight=-0.3,
                       enabled=True),
            Connection(innovation_number=18,
                       input_node=4,
                       output_node=15,
                       weight=0.6,
                       enabled=True),
            Connection(innovation_number=13,
                       input_node=10,
                       output_node=4,
                       weight=1.6,
                       enabled=True),
            Connection(innovation_number=19,
                       input_node=15,
                       output_node=4,
                       weight=-0.6,
                       enabled=True),
            Connection(innovation_number=14,
                       input_node=3,
                       output_node=4,
                       weight=-0.3,
                       enabled=True),
        ]

        self.genome_recurrent = Genome(20, self.nodes_recurrent,
                                       self.connections_recurrent)

        self.net_recurrent = BasicNeuralNetwork()
Exemple #18
0
    def setUp(self) -> None:
        self.nodes_recurrent = [
            Node(1, NodeType.INPUT, 1.0, lambda x: x, x_position=0),
            Node(2, NodeType.INPUT, 1.2, lambda x: x, x_position=0),
            Node(3, NodeType.INPUT, 1.3, lambda x: x, x_position=0),
            Node(4, NodeType.OUTPUT, 1.4, lambda x: x, x_position=1),
            Node(10, NodeType.HIDDEN, 1.5, lambda x: x, x_position=0.5),
            Node(15, NodeType.HIDDEN, 1.6, lambda x: x, x_position=0.5),
        ]

        self.connections_recurrent = [
            Connection(innovation_number=11,
                       input_node=1,
                       output_node=10,
                       weight=0.5,
                       enabled=True),
            Connection(innovation_number=12,
                       input_node=2,
                       output_node=10,
                       weight=-0.3,
                       enabled=False),
            Connection(innovation_number=22,
                       input_node=10,
                       output_node=10,
                       weight=1.5,
                       enabled=True),
            Connection(innovation_number=21,
                       input_node=15,
                       output_node=10,
                       weight=-0.1,
                       enabled=False),
            Connection(innovation_number=16,
                       input_node=2,
                       output_node=15,
                       weight=2.0,
                       enabled=True),
            Connection(innovation_number=17,
                       input_node=3,
                       output_node=15,
                       weight=-1.6,
                       enabled=True),
            Connection(innovation_number=20,
                       input_node=10,
                       output_node=15,
                       weight=-0.3,
                       enabled=True),
            Connection(innovation_number=18,
                       input_node=4,
                       output_node=15,
                       weight=0.6,
                       enabled=True),
            Connection(innovation_number=13,
                       input_node=10,
                       output_node=4,
                       weight=1.6,
                       enabled=True),
            Connection(innovation_number=19,
                       input_node=15,
                       output_node=4,
                       weight=-0.6,
                       enabled=True),
            Connection(innovation_number=14,
                       input_node=3,
                       output_node=4,
                       weight=-0.3,
                       enabled=True),
        ]

        self.genome_recurrent = Genome(20, self.nodes_recurrent,
                                       self.connections_recurrent)
    def test_cross_over(self):
        node1_1 = Node(1, NodeType.INPUT, 1.1, step_activation, 0)
        node1_2 = Node(2, NodeType.INPUT, 1.2, step_activation, 0)
        node1_5 = Node(5, NodeType.OUTPUT, 1.5, step_activation, 1)
        node1_7 = Node(7, NodeType.HIDDEN, 1.7, step_activation, 0.5)
        nodes1 = [node1_1, node1_2, node1_5, node1_7]

        node2_1 = Node(1, NodeType.INPUT, 2.1, modified_sigmoid_activation, 0)
        node2_2 = Node(2, NodeType.INPUT, 2.2, modified_sigmoid_activation, 0)
        node2_4 = Node(4, NodeType.OUTPUT, 2.4, modified_sigmoid_activation, 1)
        node2_7 = Node(7, NodeType.HIDDEN, 2.7, modified_sigmoid_activation, 0.5)
        node2_8 = Node(8, NodeType.HIDDEN, 2.8, modified_sigmoid_activation, 0.5)
        nodes2 = [node2_1, node2_2, node2_4, node2_7, node2_8]

        connection1_1 = Connection(innovation_number=1, input_node=1, output_node=2, weight=1.2, enabled=False)
        connection1_2 = Connection(innovation_number=2, input_node=1, output_node=2, weight=1.2, enabled=True)
        connection1_4 = Connection(innovation_number=4, input_node=1, output_node=2, weight=1.2, enabled=True)
        connection1_7 = Connection(innovation_number=7, input_node=1, output_node=2, weight=1.2, enabled=False)
        connections1 = [connection1_1, connection1_2, connection1_4, connection1_7]

        connection2_1 = Connection(innovation_number=1, input_node=1, output_node=2, weight=1.2, enabled=False)
        connection2_2 = Connection(innovation_number=2, input_node=1, output_node=2, weight=1.2, enabled=True)
        connection2_3 = Connection(innovation_number=3, input_node=1, output_node=2, weight=1.2, enabled=True)
        connection2_5 = Connection(innovation_number=5, input_node=1, output_node=2, weight=1.2, enabled=True)
        connection2_7 = Connection(innovation_number=7, input_node=1, output_node=2, weight=1.2, enabled=False)
        connections2 = [connection2_1, connection2_2, connection2_3, connection2_5, connection2_7]

        more_fit_parent = Genome(1, nodes1, connections1)
        less_fit_parent = Genome(2, nodes2, connections2)

        config = NeatConfig(probability_enable_gene=0.31)
        # Random values:
        # 1 rnd.uniform(0, 1) = 0.417022004702574 -> First node (node1_1)
        # 1 rnd.uniform(0, 1) = 0.7203244934421581 -> Second node(node2_2)
        # 1 rnd.uniform(0, 1) = 0.00011437481734488664 -> First node (node7_1)

        # 1 rnd.uniform(0, 1) = 0.30233257263183977 -> Select first connection (connection1_1)
        # 1 rnd.uniform(0, 1) = 0.14675589081711304 -> Re-enable connection (connection1_1)
        # 1 rnd.uniform(0, 1) = 0.0923385947687978 -> Select first connection (connection1_2)
        # 1 rnd.uniform(0, 1) = 0.1862602113776709 -> Select first connection (connection1_7)
        # 1 rnd.uniform(0, 1) = 0.34556072704304774 -> Re-enable connection False (connection1_7)

        child_nodes, child_connections = cross_over(more_fit_parent, less_fit_parent, self.rnd, config)
        # Check nodes
        self.assertEqual(4, len(child_nodes))
        self.compare_nodes(node1_1, child_nodes[0])
        self.compare_nodes(node2_2, child_nodes[1])
        self.compare_nodes(node1_5, child_nodes[2])
        self.compare_nodes(node1_7, child_nodes[3])

        # Check connections
        self.assertEqual(4, len(child_connections))
        connection1_1.enabled = True
        self.compare_connections(connection1_1, child_connections[0])
        self.compare_connections(connection1_2, child_connections[1])
        self.compare_connections(connection1_4, child_connections[2])
        self.compare_connections(connection1_7, child_connections[3])
def mutate_add_connection(genome: Genome, rnd: np.random.RandomState,
                          generator: InnovationNumberGeneratorInterface,
                          config: NeatConfig) -> (Genome, Connection):
    """
    Mutate the genome and add a new connection (if possible). The in and out node of the connection are chosen
    randomly with the given rnd generator, as well as the weight. If the in the config, recurrent networks are set to
    False, only feed forward connections can be made.
    :param genome: genome that should be modified
    :param rnd: the random generator
    :param generator: to generate innovation numbers
    :param config: the config that specifies, where and how the connection is created
    :return: the modified genome and the newly created connection. If adding a connection failed, it will be None
    """
    # Check if connection should be mutated at all
    if rnd.uniform(0, 1) > config.probability_mutate_add_connection:
        return genome, None

    # Sort nodes
    sorted_nodes = genome.nodes.copy()
    sorted_nodes.sort(key=lambda node: node.x_position)

    # List with hidden and output nodes
    hidden_output_nodes = list(
        filter(lambda node: node.node_type != NodeType.INPUT, sorted_nodes))

    # If a selection is not possible, retry the specified amount of times
    for _ in range(config.mutate_connection_tries):
        in_node = sorted_nodes[rnd.randint(len(sorted_nodes))]

        if config.allow_recurrent:
            # In recurrent networks, all nodes except input nodes can be output nodes
            possible_out_nodes = hidden_output_nodes
        else:
            # Feed forward networks, require additional, that the x position of the in_node is smaller
            possible_out_nodes = filter(
                lambda node: in_node.x_position < node.x_position,
                hidden_output_nodes)

        # Convert from iterable to list
        possible_out_nodes = list(possible_out_nodes)
        if len(possible_out_nodes) == 0:
            continue

        out_node = possible_out_nodes[rnd.randint(len(possible_out_nodes))]

        # Check if connection already exists
        exists = any(connection.input_node == in_node.innovation_number
                     and connection.output_node == out_node.innovation_number
                     for connection in genome.connections)
        # Double connections are not allowed
        if exists:
            continue

        innovation_number = generator.get_connection_innovation_number(
            in_node, out_node)
        new_connection = Connection(innovation_number,
                                    in_node.innovation_number,
                                    out_node.innovation_number,
                                    weight=rnd.uniform(
                                        config.connection_initial_min_weight,
                                        config.connection_initial_max_weight),
                                    enabled=True)

        genome.connections.append(new_connection)
        return genome, new_connection

    return genome, None