Exemple #1
0
    def __init__(self,
                 input_size=2,
                 output_size=2,
                 weight_low=-2,
                 weight_high=2,
                 depth=3):
        """
        Builds empty genome.

        :param input_size: Number of input nodes
        :param output_size: Number of output nodes
        :param weight_low: Maximum weight on node and edges
        :param weight_high: Minimum weight on node and edges
        :param depth: Number of layers in network.
        """

        self.depth = depth
        self.weight_low = weight_low
        self.weight_high = weight_high
        self.edge_innovs = set()

        self.inputs = [Node(0, i, 0, type='input') for i in range(input_size)]
        self.outputs = [
            Node(1 + depth, j, 0, type='output') for j in range(output_size)
        ]
        self.layers = None
        self.nodes = []
        self.edges = []
        self.fitness = None
Exemple #2
0
 def test_node_copy(self):
     n = Node(0, 0, 0)
     m = Node.copy(n)
     self.assertNotEqual(n, m)
     self.assertEqual(n.innov, m.innov)
     self.assertEqual(n.layer_num, m.layer_num)
     self.assertEqual(n.layer_ind, m.layer_ind)
Exemple #3
0
    def test_node_init(self):
        n1 = Node(0, 0, 0)
        n2 = Node(0, 1, 0)
        n3 = Node(1, 0, 0)
        n4 = Node(1, 1, 0)

        # Check correct nodes
        self.assertEqual(n1.innov, 0)
        self.assertEqual(n2.innov, 1)
        self.assertEqual(n3.innov, 2)
        self.assertEqual(n4.innov, 3)
Exemple #4
0
    def test_edge_init(self):

        n = Node(0, 0, 0)
        m = Node(0, 1, 0)
        with self.assertRaises(Exception) as context:
            Edge(n, m, 0)

        err_msg = 'Cannot connect edge to lower or same layer'
        self.assertTrue(err_msg == str(context.exception))

        k = Node(1, 0, 0)
        e = Edge(n, k, 0)
        self.assertEqual(e.from_node, n)
        self.assertEqual(e.to_node, k)
Exemple #5
0
def copy(genome):
    """Deep copy of genome instance.

    :param genome: Instance of Genome class
    :return: Copied instance of Genome glass
    """
    new_genome = Genome(
        input_size=len(genome.inputs),
        output_size=len(genome.outputs),
        weight_low=genome.weight_low,
        weight_high=genome.weight_high,
        depth=genome.depth)
    layers = [[Node.copy(node) for node in layer]
              for layer in genome.layers[1:-1]]
    new_genome.layers = [
        new_genome.inputs,
        *layers,
        new_genome.outputs
    ]
    nodes = [new_genome.layers[node.layer_num][node.layer_ind]
             for node in genome.nodes]
    new_genome.nodes = nodes
    for edge in genome.edges:
        new_edge = Edge.copy(edge, new_genome)
        new_genome.edge_innovs.add((
            new_edge.from_node.innov,
            new_edge.to_node.innov))
    return new_genome
Exemple #6
0
def genome_pair_factory(weight_gen=default_gen(), bias_gen=default_gen()):
    Node.innov_iter = itertools.count()
    Edge.innov_iter = itertools.count()

    np.random.seed(1)

    g1 = minimal(input_size=2, output_size=3, depth=5)
    n1 = g1.add_node(4)
    g1.add_edge(g1.layers[0][0], n1)
    g1.add_edge(n1, g1.outputs[0])

    n2 = g1.add_node(3)
    g1.add_edge(g1.layers[0][1], n2)
    g1.add_edge(n2, g1.outputs[2])

    g2 = copy(g1)

    n4 = g2.add_node(2)
    g2.add_edge(g2.layers[0][1], n4)
    g2.add_edge(n4, g2.layers[3][0])

    n5 = g1.add_node(4)
    g1.add_edge(g1.layers[3][0], n5)
    g1.add_edge(n5, g1.outputs[0])

    n3 = g1.add_node(3)
    e1 = g1.add_edge(g1.layers[0][0], n3)
    e2 = g1.add_edge(n3, g1.outputs[2])
    g2.layers[3].append(Node.copy(n3))
    g2.nodes.append(Node.copy(n3))

    n6 = g1.add_node(3)
    g1.add_edge(g1.layers[0][0], n6)
    g1.add_edge(n6, g1.outputs[1])

    g2.add_edge(g2.layers[0][0], n3)
    e2 = g2.add_edge(n3, g2.outputs[2])

    for w, edge in zip(weight_gen, [*g1.edges, *g2.edges]):
        edge.weight = w
    for w, node in zip(bias_gen, [*g1.nodes, *g2.nodes]):
        node.weight = w

    return g1, g2
Exemple #7
0
    def add_node(self, layer_num):
        """Add node to genome layer.

        :param layer_num: layer to add node too. Must be less than depth.
        :raises ValueError: If attempt to add node to input or output layers.
        :return: The new node.
        """
        if layer_num == 0 or layer_num == len(self.layers) - 1:
            raise ValueError('Cannot add node to input or output layer')
        new_node = Node(layer_num, len(self.layers[layer_num]),
                        sample_weight(self.weight_low, self.weight_high))
        self.layers[layer_num].append(new_node)
        if self.nodes and new_node.innov > self.nodes[-1].innov:
            self.nodes.append(new_node)
        else:
            self.nodes = [n for n in self.nodes if n.innov < new_node.innov] + [new_node] \
                + [n for n  in self.nodes if n.innov > new_node.innov]
        return new_node
Exemple #8
0
def from_genes(
        nodes_genes,
        edges,
        input_size=2,
        output_size=2,
        weight_low=-2,
        weight_high=2,
        depth=3):
    """Reconstructs a Genome class from the return value
    to_reduced_repr called on an instance of a Genome class.

    :param nodes_genes: First member of genome.to_reduced_repr,
        list of node properties and indices tuples. Takes form:

        [(layer_num, layer_ind, innov, weight, type), ...]

        where layer number is the genome layer index, layer_ind
        is the index in the layer, innov is the innovation number.
        weight is the node bias and type is one of 'input',
        'hidden' or 'output'.
    :param edges: Second member of genome.to_reduced_repr,
        tuple of edge properties and indices. Takes form:

        [(
            from_node.to_reduced_repr,
            to_node.to_reduced_repr,
            weight,
            innov,
            active
        ), ...]

        where from_node.to_reduced_repr and
        to_node.to_reduced_repr take the same form as an
        individual node in node_genes. weight is the
        edge weight, innov it's innovation number and
        active is True or False.
    :param input_size: Number of input nodes
    :param output_size: Number of output nodes
    :param weight_low: Maximum weight on node and edges
    :param weight_high: Minimum weight on node and edges
    :param depth: Number of layers in network.
    :return: Constructed genome.
    """

    new_genome = Genome(
        input_size=input_size,
        output_size=output_size,
        weight_low=weight_low,
        weight_high=weight_high,
        depth=depth)

    layer_maxes = [0 for _ in range(depth)]
    for node_gene in nodes_genes:
        layer_num, layer_ind, _, weight, _ = node_gene
        if layer_maxes[layer_num - 1] < layer_ind + 1:
            layer_maxes[layer_num - 1] = layer_ind + 1

    layers = []
    for layer_max in layer_maxes:
        layers.append([None for _ in range(layer_max)])

    nodes = []
    for node_gene in nodes_genes:
        layer_num, layer_ind, innov, weight, node_type = node_gene
        node = Node(layer_num, layer_ind, weight, type=node_type)
        nodes.append(node)
        layers[layer_num - 1][layer_ind] = node

    new_genome.layers = [new_genome.inputs, *layers, new_genome.outputs]

    new_genome.nodes = nodes
    for from_node_reduced, to_node_reduced, weight, innov, active in edges:
        from_layer_num, from_layer_ind, _, _, _ = from_node_reduced
        from_node = new_genome.layers[from_layer_num][from_layer_ind]
        to_layer_num, to_layer_ind, _, _, _ = to_node_reduced
        to_node = new_genome.layers[to_layer_num][to_layer_ind]
        edge = Edge(from_node, to_node, weight, active)
        new_genome.edges.append(edge)
        new_genome.edge_innovs.add((from_node.innov, to_node.innov))
    return new_genome