def test_identify_clusters(): """Test the correct assignation of clusters.""" # Create two vertices vertex_A = [Vertex() for _ in range(4)] vertex_B = [Vertex() for _ in range(2)] # 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, 0), vertex_B[1]: (1, 0), } # Identify groups groups = [set(vertex_A), set(vertex_B)] # Identify clusters utils.identify_clusters(groups, placements) # Ensure that appropriate cluster indices are assigned to all vertices assert vertex_A[0].cluster == vertex_A[1].cluster # 1 cluster of A assert vertex_A[2].cluster == vertex_A[3].cluster # The other assert vertex_A[0].cluster != vertex_A[2].cluster # Different IDs assert vertex_B[0].cluster != vertex_B[1].cluster # Different IDs
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 make_vertices(self, model, *args, **kwargs): """Create vertices that will simulate the SDPTransmitter.""" # Build the system region self._sys_region = SystemRegion(model.machine_timestep, self.size_in, 1) # Build the filter regions in_sigs = model.get_signals_to_object(self)[InputPort.standard] self._filter_region, self._routing_region = make_filter_regions( in_sigs, model.dt, True, model.keyspaces.filter_routing_tag) # Get the resources resources = { Cores: 1, SDRAM: region_utils.sizeof_regions( [self._sys_region, self._filter_region, self._routing_region], None) } # Create the vertex self._vertex = Vertex(self._label, get_application("tx"), resources) # Return the netlist specification return netlistspec( (self._vertex, ), # Tuple is required load_function=self.load_to_machine)
def make_vertices(self, model, n_steps): # TODO remove n_steps """Construct the data which can be loaded into the memory of a SpiNNaker machine. """ # Extract all the filters from the incoming connections to build the # filter regions. signals_conns = model.get_signals_to_object(self)[InputPort.standard] self.filter_region, self.filter_routing_region = make_filter_regions( signals_conns, model.dt, True, model.keyspaces.filter_routing_tag) # Use a matrix region to record into (slightly unpleasant) self.recording_region = regions.MatrixRegion( np.zeros((self.size_in, n_steps), dtype=np.uint32)) # This isn't partitioned, so we just compute the SDRAM requirement and # return a new vertex. self.system_region = SystemRegion(model.machine_timestep, self.size_in) self.regions = [None] * 15 self.regions[0] = self.system_region self.regions[1] = self.filter_region self.regions[2] = self.filter_routing_region self.regions[14] = self.recording_region # **YUCK** resources = { Cores: 1, SDRAM: regions.utils.sizeof_regions(self.regions, None) } self.vertex = Vertex(get_application("value_sink"), resources) # Return the spec return netlistspec(self.vertex, self.load_to_machine, after_simulation_function=self.after_simulation)
def make_vertices(self, model, *args, **kwargs): """Create vertices that will simulate the SDPReceiver.""" # NOTE This approach will result in more routes being created than are # actually necessary; the way to avoid this is to modify how the # builder deals with signals when creating netlists. # Get all outgoing signals and their associated transmission parameters for signal, transmission_params in \ model.get_signals_from_object(self)[OutputPort.standard]: # Get the transform, and from this the keys transform = transmission_params.full_transform(slice_out=False) keys = [(signal, {"index": i}) for i in range(transform.shape[0])] # Create a vertex for this connection (assuming its size out <= 64) if len(keys) > 64: raise NotImplementedError( "Connection is too wide to transmit to SpiNNaker. " "Consider breaking the connection up or making the " "originating node a function of time Node." ) # Create the regions for the system sys_region = SystemRegion(model.machine_timestep, len(keys)) keys_region = KeyspacesRegion(keys, [KeyField({"cluster": "cluster"})]) # Get the resources resources = { Cores: 1, SDRAM: region_utils.sizeof_regions([sys_region, keys_region], None) } # Create the vertex v = self.connection_vertices[transmission_params] = \ Vertex(self._label, get_application("rx"), resources) self._sys_regions[v] = sys_region self._key_regions[v] = keys_region # Return the netlist specification return netlistspec(list(self.connection_vertices.values()), load_function=self.load_to_machine)
def test_multiple_source_vertices(self): """Test that each of the vertices associated with a source is correctly included in the sources of a net. """ class MyVertexSlice(VertexSlice): def __init__(self, *args, **kwargs): super(MyVertexSlice, self).__init__(*args, **kwargs) self.args = None def transmits_signal(self, signal_parameters, transmission_parameters): self.args = (signal_parameters, transmission_parameters) return False # Create the first operator vertex_a0 = VertexSlice(slice(0, 1)) vertex_a1 = VertexSlice(slice(1, 2)) vertex_a2 = MyVertexSlice(slice(2, 3)) load_fn_a = mock.Mock(name="load function A") pre_fn_a = mock.Mock(name="pre function A") post_fn_a = mock.Mock(name="post function A") object_a = mock.Mock(name="object A") operator_a = mock.Mock(name="operator A", spec_set=["make_vertices"]) operator_a.make_vertices.return_value = \ netlistspec([vertex_a0, vertex_a1, vertex_a2], load_fn_a, pre_fn_a, post_fn_a) # Create the second operator vertex_b = Vertex() load_fn_b = mock.Mock(name="load function B") object_b = mock.Mock(name="object B") operator_b = mock.Mock(name="operator B", spec_set=["make_vertices"]) operator_b.make_vertices.return_value = \ netlistspec((vertex_b, ), load_fn_b) # Create a signal between the operators keyspace = mock.Mock(name="keyspace") keyspace.length = 32 signal_ab_parameters = SignalParameters(keyspace=keyspace, weight=43) # Create the model, add the items and then generate the netlist model = Model() model.object_operators[object_a] = operator_a model.object_operators[object_b] = operator_b model.connection_map.add_connection(operator_a, None, signal_ab_parameters, None, operator_b, None, None) netlist = model.make_netlist() # Check that the netlist is as expected assert netlist.operator_vertices == { operator_a: (vertex_a0, vertex_a1, vertex_a2), operator_b: (vertex_b, ), } assert len(netlist.nets) == 1 for net in itervalues(netlist.nets): assert net.sources == [vertex_a0, vertex_a1] assert net.sinks == [vertex_b] assert len(netlist.constraints) == 0 # Check that `transmit_signal` was called correctly sig, tp = vertex_a2.args assert sig.keyspace is keyspace assert tp is None
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