示例#1
0
def test_get_net_keyspaces():
    """Test the correct specification of keyspaces for nets."""
    # Create the vertices
    vertex_A = [Vertex() for _ in range(4)]
    vertex_B = Vertex()

    # Create placements such that vertex A and B fall on two chips and A[0] and
    # A[1] are on the same chip.
    placements = {
        vertex_A[0]: (0, 0),
        vertex_A[1]: (0, 0),
        vertex_A[2]: (0, 1),
        vertex_A[3]: (0, 1),
        vertex_B: (0, 0)
    }
    resources = {v: {} for v in placements}
    allocations = {v: {} for v in placements}

    # Create a container for the keyspaces
    ksc = KeyspaceContainer()

    # Create the nets
    nets = [
        NMNet(vertex_A, vertex_B, 1.0, ksc["nengo"](connection_id=0)),
        NMNet(vertex_B, vertex_A, 2.0, ksc["nengo"](connection_id=1)),
        NMNet(vertex_A, vertex_A, 3.0, ksc["spam"]),
    ]

    # Identify groups
    groups = [set(vertex_A)]

    # Identify clusters
    utils.identify_clusters(groups, placements)
    assert vertex_B.cluster is None  # Not clustered

    # Get the routing nets
    _, _, _, _, derived_nets = utils.get_nets_for_routing(
        resources, nets, placements, allocations)

    # Get the net keyspaces
    net_keyspaces = utils.get_net_keyspaces(placements, derived_nets)

    # Check the net keyspaces are correct
    # A -> B
    for xy, vertex in [((0, 0), vertex_A[0]), ((0, 1), vertex_A[2])]:
        net = derived_nets[nets[0]][xy]
        cluster = vertex.cluster
        assert net_keyspaces[net] == nets[0].keyspace(cluster=cluster)

    # B -> A
    net = derived_nets[nets[1]][(0, 0)]
    assert net_keyspaces[net] == nets[1].keyspace(cluster=0)

    # A -> A
    for xy in [(0, 0), (0, 1)]:
        net = derived_nets[nets[2]][xy]
        assert net_keyspaces[net] == nets[2].keyspace  # No change
def test_get_net_keyspaces():
    """Test the correct specification of keyspaces for nets."""
    # Create the vertices
    vertex_A = [Vertex() for _ in range(4)]
    vertex_B = Vertex()

    # Create placements such that vertex A and B fall on two chips and A[0] and
    # A[1] are on the same chip.
    placements = {
        vertex_A[0]: (0, 0), vertex_A[1]: (0, 0),
        vertex_A[2]: (0, 1), vertex_A[3]: (0, 1),
        vertex_B: (0, 0)
    }
    resources = {v: {} for v in placements}
    allocations = {v: {} for v in placements}

    # Create a container for the keyspaces
    ksc = KeyspaceContainer()

    # Create the nets
    nets = [
        NMNet(vertex_A, vertex_B, 1.0, ksc["nengo"](connection_id=0)),
        NMNet(vertex_B, vertex_A, 2.0, ksc["nengo"](connection_id=1)),
        NMNet(vertex_A, vertex_A, 3.0, ksc["spam"]),
    ]

    # Identify groups
    groups = [set(vertex_A)]

    # Identify clusters
    utils.identify_clusters(groups, placements)
    assert vertex_B.cluster is None  # Not clustered

    # Get the routing nets
    _, _, _, _, derived_nets = utils.get_nets_for_routing(
        resources, nets, placements, allocations)

    # Get the net keyspaces
    net_keyspaces = utils.get_net_keyspaces(placements, derived_nets)

    # Check the net keyspaces are correct
    # A -> B
    for xy, vertex in [((0, 0), vertex_A[0]), ((0, 1), vertex_A[2])]:
        net = derived_nets[nets[0]][xy]
        cluster = vertex.cluster
        assert net_keyspaces[net] == nets[0].keyspace(cluster=cluster)

    # B -> A
    net = derived_nets[nets[1]][(0, 0)]
    assert net_keyspaces[net] == nets[1].keyspace(cluster=0)

    # A -> A
    for xy in [(0, 0), (0, 1)]:
        net = derived_nets[nets[2]][xy]
        assert net_keyspaces[net] == nets[2].keyspace  # No change
def test_get_net_keyspaces_fails_for_inconsistent_cluster():
    """Test specification of keyspaces for nets fails in the case that
    inconsistent cluster IDs are assigned (this is unlikely to happen unless a
    Net somehow ends up having two different Nengo objects in its source
    list)."""
    # Create the vertices
    vertex_A = [Vertex() for _ in range(4)]
    vertex_B = Vertex()

    # Create placements such that vertex A and B fall on two chips and A[0] and
    # A[1] are on the same chip.
    placements = {
        vertex_A[0]: (0, 0), vertex_A[1]: (0, 0),
        vertex_A[2]: (0, 1), vertex_A[3]: (0, 1),
        vertex_B: (0, 0)
    }
    resources = {v: {} for v in placements}
    allocations = {v: {} for v in placements}

    # Create a container for the keyspaces
    ksc = KeyspaceContainer()

    # Create the signals and nets
    signal_a = Signal(
        object(), [], SignalParameters(keyspace=ksc["nengo"](connection_id=0))
    )
    signal_b = Signal(
        object(), [], SignalParameters(keyspace=ksc["nengo"](connection_id=1))
    )
    signal_c = Signal(object(), [], SignalParameters(keyspace=ksc["spam"]))

    nets = {
        signal_a: NMNet(vertex_A, vertex_B, 1.0),
        signal_b: NMNet(vertex_B, vertex_A, 2.0),
        signal_c: NMNet(vertex_A, vertex_A, 3.0),
    }

    # Identify groups
    groups = [set(vertex_A)]

    # Manually identify clusters (and do it such that it is inconsistent)
    vertex_A[0].cluster = 0
    vertex_A[1].cluster = 1
    vertex_A[2].cluster = 2
    vertex_A[3].cluster = 3

    # Get the routing nets
    _, _, _, _, derived_nets = utils.get_nets_for_routing(
        resources, nets, placements, allocations)

    # Get the net keyspaces
    with pytest.raises(AssertionError):
        utils.get_net_keyspaces(placements, nets, derived_nets)
def test_get_net_keyspaces_fails_for_inconsistent_cluster():
    """Test specification of keyspaces for nets fails in the case that
    inconsistent cluster IDs are assigned (this is unlikely to happen unless a
    Net somehow ends up having two different Nengo objects in its source
    list)."""
    # Create the vertices
    vertex_A = [Vertex() for _ in range(4)]
    vertex_B = Vertex()

    # Create placements such that vertex A and B fall on two chips and A[0] and
    # A[1] are on the same chip.
    placements = {
        vertex_A[0]: (0, 0),
        vertex_A[1]: (0, 0),
        vertex_A[2]: (0, 1),
        vertex_A[3]: (0, 1),
        vertex_B: (0, 0)
    }
    resources = {v: {} for v in placements}
    allocations = {v: {} for v in placements}

    # Create a container for the keyspaces
    ksc = KeyspaceContainer()

    # Create the signals and nets
    signal_a = Signal(object(), [],
                      SignalParameters(keyspace=ksc["nengo"](connection_id=0)))
    signal_b = Signal(object(), [],
                      SignalParameters(keyspace=ksc["nengo"](connection_id=1)))
    signal_c = Signal(object(), [], SignalParameters(keyspace=ksc["spam"]))

    nets = {
        signal_a: NMNet(vertex_A, vertex_B, 1.0),
        signal_b: NMNet(vertex_B, vertex_A, 2.0),
        signal_c: NMNet(vertex_A, vertex_A, 3.0),
    }

    # Identify groups
    groups = [set(vertex_A)]

    # Manually identify clusters (and do it such that it is inconsistent)
    vertex_A[0].cluster = 0
    vertex_A[1].cluster = 1
    vertex_A[2].cluster = 2
    vertex_A[3].cluster = 3

    # Get the routing nets
    _, _, _, _, derived_nets = utils.get_nets_for_routing(
        resources, nets, placements, allocations)

    # Get the net keyspaces
    with pytest.raises(AssertionError):
        utils.get_net_keyspaces(placements, nets, derived_nets)
    def place_and_route(self, system_info,
                        place=place_and_route.place,
                        place_kwargs={},
                        allocate=place_and_route.allocate,
                        allocate_kwargs={},
                        route=place_and_route.route,
                        route_kwargs={}):
        """Place and route the netlist onto the given SpiNNaker machine.

        Parameters
        ----------
        system_info : \
                :py:class:`~rig.machine_control.MachineController.SystemInfo`
            Describes the system onto which the netlist should be placed and
            routed.

        Other Parameters
        ----------------
        place : function
            Placement function. Must support the interface defined by Rig.
        place_kwargs : dict
            Keyword arguments for the placement method.
        allocate : function
            Resource allocation function. Must support the interface defined by
            Rig.
        allocate_kwargs : dict
            Keyword arguments for the allocation function.
        route : function
            Router function. Must support the interface defined by Rig.
        route_kwargs : dict
            Keyword arguments for the router function.
        """
        # Generate a Machine and set of core-reserving constraints to prevent
        # the use of non-idle cores.
        machine = build_machine(system_info)
        core_constraints = build_core_constraints(system_info)
        constraints = self.constraints + core_constraints

        # Build a map of vertices to the resources they require, get a list of
        # constraints.
        vertices_resources = {v: v.resources for v in self.vertices}

        # Perform placement and allocation
        place_nets = list(utils.get_nets_for_placement(self.nets))
        self.placements = place(vertices_resources, place_nets, machine,
                                constraints, **place_kwargs)
        self.allocations = allocate(vertices_resources, place_nets, machine,
                                    constraints, self.placements,
                                    **allocate_kwargs)

        # Identify clusters and modify vertices appropriately
        utils.identify_clusters(self.groups, self.placements)

        # Get the nets for routing
        (route_nets,
         vertices_resources,  # Can safely overwrite the resource dictionary
         extended_placements,
         extended_allocations,
         derived_nets) = utils.get_nets_for_routing(
            vertices_resources, self.nets, self.placements, self.allocations)

        # Get a map from the nets we will route with to keyspaces
        self.net_keyspaces = utils.get_net_keyspaces(self.placements,
                                                     derived_nets)

        # Fix all keyspaces
        self.keyspaces.assign_fields()

        # Finally, route all nets using the extended resource dictionary,
        # placements and allocations.
        self.routes = route(vertices_resources, route_nets, machine,
                            constraints, extended_placements,
                            extended_allocations, **route_kwargs)
def test_get_nets_for_routing():
    """Test that Rig nets can be generated to be used during the routing."""
    # Create the vertices
    a = object()
    b = object()
    c = object()
    d = object()
    e = object()

    # Create the nets
    ab_cd = NMNet([a, b], [c, d], 1.0)
    cd_e = NMNet([c, d], e, 2.0)

    # Create some signals
    signal_a = object()
    signal_b = object()
    nets = {signal_a: ab_cd, signal_b: cd_e}

    # Create some placements:
    #  - a and b placed on the same chip
    #  - c and d placed on different chips
    placements = {a: (0, 0), b: (0, 0),
                  c: (1, 0), d: (0, 1), e: (1, 1)}

    # Create some resource requirements
    vertices_resources = {a: {Cores: 1},
                          b: {Cores: 2},
                          c: {Cores: 3},
                          d: {Cores: 4},
                          e: {Cores: 5}}

    # And create some sample allocations
    allocations = {a: {Cores: slice(1, 2)},
                   b: {Cores: slice(2, 4)},
                   c: {Cores: slice(1, 4)},
                   d: {Cores: slice(1, 5)},
                   e: {Cores: slice(1, 6)}}

    # Get the routing nets
    (routing_nets, extended_resources, extended_placements,
     extended_allocations, derived_nets) = utils.get_nets_for_routing(
        vertices_resources, nets, placements, allocations)

    # Check that the routing nets are sane
    assert len(routing_nets) == 3
    seen_cd_placements = set()
    expected_cd_placements = {placements[c], placements[d]}

    for net in routing_nets:
        # Check the sources is in the extended allocations and resources.
        assert extended_resources[net.source] == dict()
        assert extended_allocations[net.source] == dict()

        if net.sinks == [c, d]:
            assert net.weight == ab_cd.weight

            # Source should have been a and b, check the extended placement is
            # correct
            assert net.source not in placements
            assert extended_placements[net.source] == placements[a]
            assert extended_placements[net.source] == placements[b]

            # Check that the net is correctly identified in the derived nets
            # mapping.
            assert derived_nets[ab_cd][placements[a]] is net
        else:
            assert net.sinks == [e]
            assert net.weight == cd_e.weight

            # Source should have been one of c or d, check that the placement
            # is appropriate.
            assert net.source not in placements
            placement = extended_placements[net.source]
            assert placement in expected_cd_placements
            assert placement not in seen_cd_placements
            seen_cd_placements.add(placement)

            # Check that the net is correctly identified in the derived nets
            # mapping.
            assert derived_nets[cd_e][placement] is net

    assert seen_cd_placements == expected_cd_placements

    # Check that the original vertices are still present in the extended
    # placements.
    for v in [a, b, c, d, e]:
        assert extended_placements[v] == placements[v]
        assert extended_resources[v] == vertices_resources[v]
        assert extended_allocations[v] == allocations[v]
def test_get_net_keyspaces():
    """Test the correct specification of keyspaces for nets."""
    # Create the vertices
    vertex_A = [Vertex() for _ in range(4)]
    vertex_B = Vertex()

    # Create placements such that vertex A and B fall on two chips and A[0] and
    # A[1] are on the same chip.
    placements = {
        vertex_A[0]: (0, 0), vertex_A[1]: (0, 0),
        vertex_A[2]: (0, 1), vertex_A[3]: (0, 1),
        vertex_B: (0, 0)
    }
    resources = {v: {} for v in placements}
    allocations = {v: {} for v in placements}

    # Manually assign cluster IDs
    vertex_A[0].cluster = 0
    vertex_A[1].cluster = 0
    vertex_A[2].cluster = 1
    vertex_A[3].cluster = 1

    # Create a container for the keyspaces
    ksc = KeyspaceContainer()

    # Create the signals and nets
    signal_a = Signal(
        object(), [], SignalParameters(keyspace=ksc["nengo"](connection_id=0))
    )
    signal_b = Signal(
        object(), [], SignalParameters(keyspace=ksc["nengo"](connection_id=1))
    )
    signal_c = Signal(object(), [], SignalParameters(keyspace=ksc["spam"]))

    nets = {
        signal_a: NMNet(vertex_A, vertex_B, 1.0),
        signal_b: NMNet(vertex_B, vertex_A, 2.0),
        signal_c: NMNet(vertex_A, vertex_A, 3.0),
    }

    # Get the routing nets
    _, _, _, _, derived_nets = utils.get_nets_for_routing(
        resources, nets, placements, allocations)

    # Get the net keyspaces
    net_keyspaces = utils.get_net_keyspaces(placements, nets, derived_nets)

    # Check the net keyspaces are correct
    # A -> B
    for xy, vertex in [((0, 0), vertex_A[0]), ((0, 1), vertex_A[2])]:
        net = derived_nets[nets[signal_a]][xy]
        cluster = vertex.cluster
        assert net_keyspaces[net] == signal_a.keyspace(cluster=cluster)

    # B -> A
    net = derived_nets[nets[signal_b]][(0, 0)]
    assert net_keyspaces[net] == signal_b.keyspace(cluster=0)

    # A -> A
    for xy in [(0, 0), (0, 1)]:
        net = derived_nets[nets[signal_c]][xy]
        assert net_keyspaces[net] == signal_c.keyspace  # No change
示例#8
0
    def place_and_route(self,
                        system_info,
                        place=place_and_route.place,
                        place_kwargs={},
                        allocate=place_and_route.allocate,
                        allocate_kwargs={},
                        route=place_and_route.route,
                        route_kwargs={}):
        """Place and route the netlist onto the given SpiNNaker machine.

        Parameters
        ----------
        system_info : \
                :py:class:`~rig.machine_control.MachineController.SystemInfo`
            Describes the system onto which the netlist should be placed and
            routed.

        Other Parameters
        ----------------
        place : function
            Placement function. Must support the interface defined by Rig.
        place_kwargs : dict
            Keyword arguments for the placement method.
        allocate : function
            Resource allocation function. Must support the interface defined by
            Rig.
        allocate_kwargs : dict
            Keyword arguments for the allocation function.
        route : function
            Router function. Must support the interface defined by Rig.
        route_kwargs : dict
            Keyword arguments for the router function.
        """
        # Generate a Machine and set of core-reserving constraints to prevent
        # the use of non-idle cores.
        machine = build_machine(system_info)
        core_constraints = build_core_constraints(system_info)
        constraints = self.constraints + core_constraints

        # Build a map of vertices to the resources they require, get a list of
        # constraints.
        vertices_resources = {v: v.resources for v in self.vertices}

        # Perform placement and allocation
        place_nets = list(utils.get_nets_for_placement(itervalues(self.nets)))
        self.placements = place(vertices_resources, place_nets, machine,
                                constraints, **place_kwargs)
        self.allocations = allocate(vertices_resources, place_nets, machine,
                                    constraints, self.placements,
                                    **allocate_kwargs)

        # Get the nets for routing
        (
            route_nets,
            vertices_resources,  # Can safely overwrite the resource dictionary
            extended_placements,
            extended_allocations,
            derived_nets) = utils.get_nets_for_routing(vertices_resources,
                                                       self.nets,
                                                       self.placements,
                                                       self.allocations)

        # Finally, route all nets using the extended resource dictionary,
        # placements and allocations.
        self.routes = route(vertices_resources, route_nets, machine,
                            constraints, extended_placements,
                            extended_allocations, **route_kwargs)

        # Assign keyspaces based on the placement
        signal_routes = collections.defaultdict(collections.deque)
        for signal, nmnet in iteritems(self.nets):
            for net in itervalues(derived_nets[nmnet]):
                signal_routes[signal].append(self.routes[net])

        key_allocation.allocate_signal_keyspaces(signal_routes,
                                                 self.signal_id_constraints,
                                                 self.keyspaces)

        # Assign cluster IDs based on the placement and the routing
        key_allocation.assign_cluster_ids(self.operator_vertices,
                                          signal_routes, self.placements)

        # Get a map from the nets we will route with to keyspaces
        self.net_keyspaces = utils.get_net_keyspaces(self.placements,
                                                     self.nets, derived_nets)

        # Fix all keyspaces
        self.keyspaces.assign_fields()
def test_get_nets_for_routing():
    """Test that Rig nets can be generated to be used during the routing."""
    # Create the vertices
    a = object()
    b = object()
    c = object()
    d = object()
    e = object()

    # Create the nets
    ab_cd = NMNet([a, b], [c, d], 1.0)
    cd_e = NMNet([c, d], e, 2.0)

    # Create some signals
    signal_a = object()
    signal_b = object()
    nets = {signal_a: ab_cd, signal_b: cd_e}

    # Create some placements:
    #  - a and b placed on the same chip
    #  - c and d placed on different chips
    placements = {a: (0, 0), b: (0, 0), c: (1, 0), d: (0, 1), e: (1, 1)}

    # Create some resource requirements
    vertices_resources = {
        a: {
            Cores: 1
        },
        b: {
            Cores: 2
        },
        c: {
            Cores: 3
        },
        d: {
            Cores: 4
        },
        e: {
            Cores: 5
        }
    }

    # And create some sample allocations
    allocations = {
        a: {
            Cores: slice(1, 2)
        },
        b: {
            Cores: slice(2, 4)
        },
        c: {
            Cores: slice(1, 4)
        },
        d: {
            Cores: slice(1, 5)
        },
        e: {
            Cores: slice(1, 6)
        }
    }

    # Get the routing nets
    (routing_nets, extended_resources, extended_placements,
     extended_allocations,
     derived_nets) = utils.get_nets_for_routing(vertices_resources, nets,
                                                placements, allocations)

    # Check that the routing nets are sane
    assert len(routing_nets) == 3
    seen_cd_placements = set()
    expected_cd_placements = {placements[c], placements[d]}

    for net in routing_nets:
        # Check the sources is in the extended allocations and resources.
        assert extended_resources[net.source] == dict()
        assert extended_allocations[net.source] == dict()

        if net.sinks == [c, d]:
            assert net.weight == ab_cd.weight

            # Source should have been a and b, check the extended placement is
            # correct
            assert net.source not in placements
            assert extended_placements[net.source] == placements[a]
            assert extended_placements[net.source] == placements[b]

            # Check that the net is correctly identified in the derived nets
            # mapping.
            assert derived_nets[ab_cd][placements[a]] is net
        else:
            assert net.sinks == [e]
            assert net.weight == cd_e.weight

            # Source should have been one of c or d, check that the placement
            # is appropriate.
            assert net.source not in placements
            placement = extended_placements[net.source]
            assert placement in expected_cd_placements
            assert placement not in seen_cd_placements
            seen_cd_placements.add(placement)

            # Check that the net is correctly identified in the derived nets
            # mapping.
            assert derived_nets[cd_e][placement] is net

    assert seen_cd_placements == expected_cd_placements

    # Check that the original vertices are still present in the extended
    # placements.
    for v in [a, b, c, d, e]:
        assert extended_placements[v] == placements[v]
        assert extended_resources[v] == vertices_resources[v]
        assert extended_allocations[v] == allocations[v]
def test_get_net_keyspaces():
    """Test the correct specification of keyspaces for nets."""
    # Create the vertices
    vertex_A = [Vertex() for _ in range(4)]
    vertex_B = Vertex()

    # Create placements such that vertex A and B fall on two chips and A[0] and
    # A[1] are on the same chip.
    placements = {
        vertex_A[0]: (0, 0),
        vertex_A[1]: (0, 0),
        vertex_A[2]: (0, 1),
        vertex_A[3]: (0, 1),
        vertex_B: (0, 0)
    }
    resources = {v: {} for v in placements}
    allocations = {v: {} for v in placements}

    # Manually assign cluster IDs
    vertex_A[0].cluster = 0
    vertex_A[1].cluster = 0
    vertex_A[2].cluster = 1
    vertex_A[3].cluster = 1

    # Create a container for the keyspaces
    ksc = KeyspaceContainer()

    # Create the signals and nets
    signal_a = Signal(object(), [],
                      SignalParameters(keyspace=ksc["nengo"](connection_id=0)))
    signal_b = Signal(object(), [],
                      SignalParameters(keyspace=ksc["nengo"](connection_id=1)))
    signal_c = Signal(object(), [], SignalParameters(keyspace=ksc["spam"]))

    nets = {
        signal_a: NMNet(vertex_A, vertex_B, 1.0),
        signal_b: NMNet(vertex_B, vertex_A, 2.0),
        signal_c: NMNet(vertex_A, vertex_A, 3.0),
    }

    # Get the routing nets
    _, _, _, _, derived_nets = utils.get_nets_for_routing(
        resources, nets, placements, allocations)

    # Get the net keyspaces
    net_keyspaces = utils.get_net_keyspaces(placements, nets, derived_nets)

    # Check the net keyspaces are correct
    # A -> B
    for xy, vertex in [((0, 0), vertex_A[0]), ((0, 1), vertex_A[2])]:
        net = derived_nets[nets[signal_a]][xy]
        cluster = vertex.cluster
        assert net_keyspaces[net] == signal_a.keyspace(cluster=cluster)

    # B -> A
    net = derived_nets[nets[signal_b]][(0, 0)]
    assert net_keyspaces[net] == signal_b.keyspace(cluster=0)

    # A -> A
    for xy in [(0, 0), (0, 1)]:
        net = derived_nets[nets[signal_c]][xy]
        assert net_keyspaces[net] == signal_c.keyspace  # No change